blob: 29c473e569268ae5cb825808cb2e11ac8ade7d4a [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
15#include "libxml.h"
16
17#ifdef LIBXML_CATALOG_ENABLED
18#ifdef HAVE_SYS_TYPES_H
19#include <sys/types.h>
20#endif
21#ifdef HAVE_SYS_STAT_H
22#include <sys/stat.h>
23#endif
24#ifdef HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27#ifdef HAVE_FCNTL_H
28#include <fcntl.h>
29#endif
Daniel Veillardc0631a62001-09-20 13:56:06 +000030#ifdef HAVE_STDLIB_H
31#include <stdlib.h>
32#endif
Daniel Veillarda7374592001-05-10 14:17:55 +000033#include <string.h>
34#include <libxml/xmlmemory.h>
35#include <libxml/hash.h>
36#include <libxml/uri.h>
37#include <libxml/parserInternals.h>
38#include <libxml/catalog.h>
39#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000040#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000041#include <libxml/globals.h>
Daniel Veillarda7374592001-05-10 14:17:55 +000042
Daniel Veillard6990bf32001-08-23 21:17:48 +000043#define MAX_DELEGATE 50
44
Daniel Veillard344cee72001-08-20 00:08:40 +000045/**
46 * TODO:
47 *
48 * macro to flag unimplemented blocks
49 */
50#define TODO \
51 xmlGenericError(xmlGenericErrorContext, \
52 "Unimplemented block at %s:%d\n", \
53 __FILE__, __LINE__);
54
Daniel Veillardcda96922001-08-21 10:56:31 +000055#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000056#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000057#ifndef XML_XML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000058#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000059#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000060#ifndef XML_SGML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000061#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
Daniel Veillard75b96822001-10-11 18:59:45 +000062#endif
63
Daniel Veillard85c11fa2001-10-16 21:03:08 +000064static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000065
Daniel Veillarda7374592001-05-10 14:17:55 +000066/************************************************************************
67 * *
68 * Types, all private *
69 * *
70 ************************************************************************/
71
72typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +000073 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +000074 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000075 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000076 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000077 XML_CATA_NEXT_CATALOG,
78 XML_CATA_PUBLIC,
79 XML_CATA_SYSTEM,
80 XML_CATA_REWRITE_SYSTEM,
81 XML_CATA_DELEGATE_PUBLIC,
82 XML_CATA_DELEGATE_SYSTEM,
83 XML_CATA_URI,
84 XML_CATA_REWRITE_URI,
85 XML_CATA_DELEGATE_URI,
86 SGML_CATA_SYSTEM,
87 SGML_CATA_PUBLIC,
88 SGML_CATA_ENTITY,
89 SGML_CATA_PENTITY,
90 SGML_CATA_DOCTYPE,
91 SGML_CATA_LINKTYPE,
92 SGML_CATA_NOTATION,
93 SGML_CATA_DELEGATE,
94 SGML_CATA_BASE,
95 SGML_CATA_CATALOG,
96 SGML_CATA_DOCUMENT,
97 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000098} xmlCatalogEntryType;
99
100typedef struct _xmlCatalogEntry xmlCatalogEntry;
101typedef xmlCatalogEntry *xmlCatalogEntryPtr;
102struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000103 struct _xmlCatalogEntry *next;
104 struct _xmlCatalogEntry *parent;
105 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000106 xmlCatalogEntryType type;
107 xmlChar *name;
108 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000109 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000110 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000111 int dealloc;
Daniel Veillarda7374592001-05-10 14:17:55 +0000112};
113
Daniel Veillard75b96822001-10-11 18:59:45 +0000114typedef enum {
115 XML_XML_CATALOG_TYPE = 1,
116 XML_SGML_CATALOG_TYPE
117} xmlCatalogType;
118
119#define XML_MAX_SGML_CATA_DEPTH 10
120struct _xmlCatalog {
121 xmlCatalogType type; /* either XML or SGML */
122
123 /*
124 * SGML Catalogs are stored as a simple hash table of catalog entries
125 * Catalog stack to check against overflows when building the
126 * SGML catalog
127 */
128 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
129 int catalNr; /* Number of current catal streams */
130 int catalMax; /* Max number of catal streams */
131 xmlHashTablePtr sgml;
132
133 /*
134 * XML Catalogs are stored as a tree of Catalog entries
135 */
136 xmlCatalogPrefer prefer;
137 xmlCatalogEntryPtr xml;
138};
139
140/************************************************************************
141 * *
142 * Global variables *
143 * *
144 ************************************************************************/
145
Daniel Veillard81463942001-10-16 12:34:39 +0000146/*
147 * Those are preferences
148 */
149static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000150static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000151static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000152
153/*
154 * Hash table containing all the trees of XML catalogs parsed by
155 * the application.
156 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000157static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000158
159/*
160 * The default catalog in use by the application
161 */
162static xmlCatalogPtr xmlDefaultCatalog = NULL;
163
164/*
Daniel Veillard81463942001-10-16 12:34:39 +0000165 * A mutex for modifying the shared global catalog(s)
166 * xmlDefaultCatalog tree.
167 * It also protects xmlCatalogXMLFiles
168 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
169 */
170static xmlRMutexPtr xmlCatalogMutex = NULL;
171
172/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000173 * Whether the catalog support was initialized.
174 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000175static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000176
Daniel Veillarda7374592001-05-10 14:17:55 +0000177
178/************************************************************************
179 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000180 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000181 * *
182 ************************************************************************/
183
Daniel Veillard75b96822001-10-11 18:59:45 +0000184/**
185 * xmlNewCatalogEntry:
186 * @type: type of entry
187 * @name: name of the entry
188 * @value: value of the entry
189 * @prefer: the PUBLIC vs. SYSTEM current preference value
190 *
191 * create a new Catalog entry, this type is shared both by XML and
192 * SGML catalogs, but the acceptable types values differs.
193 *
194 * Returns the xmlCatalogEntryPtr or NULL in case of error
195 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000196static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000197xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillardc853b322001-11-06 15:24:37 +0000198 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000199 xmlCatalogEntryPtr ret;
200
201 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
202 if (ret == NULL) {
203 xmlGenericError(xmlGenericErrorContext,
204 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
205 return(NULL);
206 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000207 ret->next = NULL;
208 ret->parent = NULL;
209 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000210 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000211 if (name != NULL)
212 ret->name = xmlStrdup(name);
213 else
214 ret->name = NULL;
215 if (value != NULL)
216 ret->value = xmlStrdup(value);
217 else
218 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000219 if (URL == NULL)
220 URL = value;
221 if (URL != NULL)
222 ret->URL = xmlStrdup(URL);
223 else
224 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000225 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000226 ret->dealloc = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +0000227 return(ret);
228}
229
230static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000231xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
232
Daniel Veillard75b96822001-10-11 18:59:45 +0000233/**
234 * xmlFreeCatalogEntry:
235 * @ret: a Catalog entry
236 *
237 * Free the memory allocated to a Catalog entry
238 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000239static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000240xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
241 if (ret == NULL)
242 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000243 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000244 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000245 * only by the file hash cleaner !
246 */
247 if (ret->dealloc == 1)
248 return;
249
250 if (xmlDebugCatalogs) {
251 if (ret->name != NULL)
252 xmlGenericError(xmlGenericErrorContext,
253 "Free catalog entry %s\n", ret->name);
254 else if (ret->value != NULL)
255 xmlGenericError(xmlGenericErrorContext,
256 "Free catalog entry %s\n", ret->value);
257 else
258 xmlGenericError(xmlGenericErrorContext,
259 "Free catalog entry\n");
260 }
261
Daniel Veillarda7374592001-05-10 14:17:55 +0000262 if (ret->name != NULL)
263 xmlFree(ret->name);
264 if (ret->value != NULL)
265 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000266 if (ret->URL != NULL)
267 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000268 xmlFree(ret);
269}
270
Daniel Veillard75b96822001-10-11 18:59:45 +0000271/**
272 * xmlFreeCatalogEntryList:
273 * @ret: a Catalog entry list
274 *
275 * Free the memory allocated to a full chained list of Catalog entries
276 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000277static void
278xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
279 xmlCatalogEntryPtr next;
280
281 while (ret != NULL) {
282 next = ret->next;
283 xmlFreeCatalogEntry(ret);
284 ret = next;
285 }
286}
287
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000288/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000289 * xmlFreeCatalogHashEntryList:
290 * @ret: a Catalog entry list
291 *
292 * Free the memory allocated to list of Catalog entries from the
293 * catalog file hash.
294 */
295static void
296xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
297 xmlCatalogEntryPtr children, next;
298
299 if (catal == NULL)
300 return;
301
302 children = catal->children;
303 while (children != NULL) {
304 next = children->next;
305 children->dealloc = 0;
306 children->children = NULL;
307 xmlFreeCatalogEntry(children);
308 children = next;
309 }
310 catal->dealloc = 0;
311 xmlFreeCatalogEntry(catal);
312}
313
314/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000315 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000316 * @type: type of catalog
317 * @prefer: the PUBLIC vs. SYSTEM current preference value
318 *
319 * create a new Catalog, this type is shared both by XML and
320 * SGML catalogs, but the acceptable types values differs.
321 *
322 * Returns the xmlCatalogPtr or NULL in case of error
323 */
324static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000325xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000326 xmlCatalogPtr ret;
327
328 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
329 if (ret == NULL) {
330 xmlGenericError(xmlGenericErrorContext,
331 "malloc of %d byte failed\n", sizeof(xmlCatalog));
332 return(NULL);
333 }
334 memset(ret, 0, sizeof(xmlCatalog));
335 ret->type = type;
336 ret->catalNr = 0;
337 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
338 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000339 if (ret->type == XML_SGML_CATALOG_TYPE)
340 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000341 return(ret);
342}
343
344/**
345 * xmlFreeCatalog:
346 * @catal: a Catalog entry
347 *
348 * Free the memory allocated to a Catalog
349 */
350void
351xmlFreeCatalog(xmlCatalogPtr catal) {
352 if (catal == NULL)
353 return;
354 if (catal->xml != NULL)
355 xmlFreeCatalogEntryList(catal->xml);
356 if (catal->sgml != NULL)
357 xmlHashFree(catal->sgml,
358 (xmlHashDeallocator) xmlFreeCatalogEntry);
359 xmlFree(catal);
360}
361
362/************************************************************************
363 * *
364 * Serializing Catalogs *
365 * *
366 ************************************************************************/
367
368/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000369 * xmlCatalogDumpEntry:
370 * @entry: the
371 * @out: the file.
372 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000373 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000374 */
375static void
376xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
377 if ((entry == NULL) || (out == NULL))
378 return;
379 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000380 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000381 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000382 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000383 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000384 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000385 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000386 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000387 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000388 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000389 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000390 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000391 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000392 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000393 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000394 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000395 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000396 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000397 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000398 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000399 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000400 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000401 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000402 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000403 fprintf(out, "SGMLDECL "); break;
404 default:
405 return;
406 }
407 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000408 case SGML_CATA_ENTITY:
409 case SGML_CATA_PENTITY:
410 case SGML_CATA_DOCTYPE:
411 case SGML_CATA_LINKTYPE:
412 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000413 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000414 case SGML_CATA_PUBLIC:
415 case SGML_CATA_SYSTEM:
416 case SGML_CATA_SGMLDECL:
417 case SGML_CATA_DOCUMENT:
418 case SGML_CATA_CATALOG:
419 case SGML_CATA_BASE:
420 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000421 fprintf(out, "\"%s\"", entry->name); break;
422 default:
423 break;
424 }
425 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000426 case SGML_CATA_ENTITY:
427 case SGML_CATA_PENTITY:
428 case SGML_CATA_DOCTYPE:
429 case SGML_CATA_LINKTYPE:
430 case SGML_CATA_NOTATION:
431 case SGML_CATA_PUBLIC:
432 case SGML_CATA_SYSTEM:
433 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000434 fprintf(out, " \"%s\"", entry->value); break;
435 default:
436 break;
437 }
438 fprintf(out, "\n");
439}
440
Daniel Veillard75b96822001-10-11 18:59:45 +0000441static int
442xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
443 int ret;
444 xmlDocPtr doc;
445 xmlNsPtr ns;
446 xmlDtdPtr dtd;
447 xmlNodePtr node, catalog;
448 xmlOutputBufferPtr buf;
449 xmlCatalogEntryPtr cur;
450
451 /*
452 * Rebuild a catalog
453 */
454 doc = xmlNewDoc(NULL);
455 if (doc == NULL)
456 return(-1);
457 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
458 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
459BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
460
461 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
462
463 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
464 if (ns == NULL) {
465 xmlFreeDoc(doc);
466 return(-1);
467 }
468 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
469 if (catalog == NULL) {
470 xmlFreeNs(ns);
471 xmlFreeDoc(doc);
472 return(-1);
473 }
474 catalog->nsDef = ns;
475 xmlAddChild((xmlNodePtr) doc, catalog);
476
477 /*
478 * add all the catalog entries
479 */
480 cur = catal;
481 while (cur != NULL) {
482 switch (cur->type) {
Daniel Veillardc853b322001-11-06 15:24:37 +0000483 case XML_CATA_REMOVED:
484 break;
Daniel Veillard75b96822001-10-11 18:59:45 +0000485 case XML_CATA_BROKEN_CATALOG:
486 case XML_CATA_CATALOG:
487 if (cur == catal) {
488 cur = cur->children;
489 continue;
490 }
491 break;
492 case XML_CATA_NEXT_CATALOG:
493 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
494 xmlSetProp(node, BAD_CAST "catalog", cur->value);
495 xmlAddChild(catalog, node);
496 break;
497 case XML_CATA_NONE:
498 break;
499 case XML_CATA_PUBLIC:
500 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
501 xmlSetProp(node, BAD_CAST "publicId", cur->name);
502 xmlSetProp(node, BAD_CAST "uri", cur->value);
503 xmlAddChild(catalog, node);
504 break;
505 case XML_CATA_SYSTEM:
506 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
507 xmlSetProp(node, BAD_CAST "systemId", cur->name);
508 xmlSetProp(node, BAD_CAST "uri", cur->value);
509 xmlAddChild(catalog, node);
510 break;
511 case XML_CATA_REWRITE_SYSTEM:
512 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
513 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
514 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
515 xmlAddChild(catalog, node);
516 break;
517 case XML_CATA_DELEGATE_PUBLIC:
518 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
519 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
520 xmlSetProp(node, BAD_CAST "catalog", cur->value);
521 xmlAddChild(catalog, node);
522 break;
523 case XML_CATA_DELEGATE_SYSTEM:
524 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
525 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
526 xmlSetProp(node, BAD_CAST "catalog", cur->value);
527 xmlAddChild(catalog, node);
528 break;
529 case XML_CATA_URI:
530 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
531 xmlSetProp(node, BAD_CAST "name", cur->name);
532 xmlSetProp(node, BAD_CAST "uri", cur->value);
533 xmlAddChild(catalog, node);
534 break;
535 case XML_CATA_REWRITE_URI:
536 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
537 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
538 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
539 xmlAddChild(catalog, node);
540 break;
541 case XML_CATA_DELEGATE_URI:
542 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
543 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
544 xmlSetProp(node, BAD_CAST "catalog", cur->value);
545 xmlAddChild(catalog, node);
546 break;
547 case SGML_CATA_SYSTEM:
548 case SGML_CATA_PUBLIC:
549 case SGML_CATA_ENTITY:
550 case SGML_CATA_PENTITY:
551 case SGML_CATA_DOCTYPE:
552 case SGML_CATA_LINKTYPE:
553 case SGML_CATA_NOTATION:
554 case SGML_CATA_DELEGATE:
555 case SGML_CATA_BASE:
556 case SGML_CATA_CATALOG:
557 case SGML_CATA_DOCUMENT:
558 case SGML_CATA_SGMLDECL:
559 break;
560 }
561 cur = cur->next;
562 }
563
564 /*
565 * reserialize it
566 */
567 buf = xmlOutputBufferCreateFile(out, NULL);
568 if (buf == NULL) {
569 xmlFreeDoc(doc);
570 return(-1);
571 }
572 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
573
574 /*
575 * Free it
576 */
577 xmlFreeDoc(doc);
578
579 return(ret);
580}
581
582/************************************************************************
583 * *
584 * Converting SGML Catalogs to XML *
585 * *
586 ************************************************************************/
587
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000588/**
589 * xmlCatalogConvertEntry:
590 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000591 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000592 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000593 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000594 */
595static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000596xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
597 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
598 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000599 return;
600 switch (entry->type) {
601 case SGML_CATA_ENTITY:
602 entry->type = XML_CATA_PUBLIC;
603 break;
604 case SGML_CATA_PENTITY:
605 entry->type = XML_CATA_PUBLIC;
606 break;
607 case SGML_CATA_DOCTYPE:
608 entry->type = XML_CATA_PUBLIC;
609 break;
610 case SGML_CATA_LINKTYPE:
611 entry->type = XML_CATA_PUBLIC;
612 break;
613 case SGML_CATA_NOTATION:
614 entry->type = XML_CATA_PUBLIC;
615 break;
616 case SGML_CATA_PUBLIC:
617 entry->type = XML_CATA_PUBLIC;
618 break;
619 case SGML_CATA_SYSTEM:
620 entry->type = XML_CATA_SYSTEM;
621 break;
622 case SGML_CATA_DELEGATE:
623 entry->type = XML_CATA_DELEGATE_PUBLIC;
624 break;
625 case SGML_CATA_CATALOG:
626 entry->type = XML_CATA_CATALOG;
627 break;
628 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000629 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000630 (xmlHashDeallocator) xmlFreeCatalogEntry);
631 return;
632 }
633 /*
634 * Conversion successful, remove from the SGML catalog
635 * and add it to the default XML one
636 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000637 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
638 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000639 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000640 if (catal->xml->children == NULL)
641 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000642 else {
643 xmlCatalogEntryPtr prev;
644
Daniel Veillard75b96822001-10-11 18:59:45 +0000645 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000646 while (prev->next != NULL)
647 prev = prev->next;
648 prev->next = entry;
649 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000650}
651
652/**
653 * xmlConvertSGMLCatalog:
654 * @catal: the catalog
655 *
656 * Convert all the SGML catalog entries as XML ones
657 *
658 * Returns the number of entries converted if successful, -1 otherwise
659 */
660int
661xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
662
663 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
664 return(-1);
665
666 if (xmlDebugCatalogs) {
667 xmlGenericError(xmlGenericErrorContext,
668 "Converting SGML catalog to XML\n");
669 }
670 xmlHashScan(catal->sgml,
671 (xmlHashScanner) xmlCatalogConvertEntry,
672 &catal);
673 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000674}
675
Daniel Veillarda7374592001-05-10 14:17:55 +0000676/************************************************************************
677 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000678 * Helper function *
679 * *
680 ************************************************************************/
681
682/**
683 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000684 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000685 *
686 * Expand the URN into the equivalent Public Identifier
687 *
688 * Returns the new identifier or NULL, the string must be deallocated
689 * by the caller.
690 */
691static xmlChar *
692xmlCatalogUnWrapURN(const xmlChar *urn) {
693 xmlChar result[2000];
694 unsigned int i = 0;
695
696 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
697 return(NULL);
698 urn += sizeof(XML_URN_PUBID) - 1;
699
700 while (*urn != 0) {
701 if (i > sizeof(result) - 3)
702 break;
703 if (*urn == '+') {
704 result[i++] = ' ';
705 urn++;
706 } else if (*urn == ':') {
707 result[i++] = '/';
708 result[i++] = '/';
709 urn++;
710 } else if (*urn == ';') {
711 result[i++] = ':';
712 result[i++] = ':';
713 urn++;
714 } else if (*urn == '%') {
715 if ((urn[1] == '2') && (urn[1] == 'B'))
716 result[i++] = '+';
717 else if ((urn[1] == '3') && (urn[1] == 'A'))
718 result[i++] = ':';
719 else if ((urn[1] == '2') && (urn[1] == 'F'))
720 result[i++] = '/';
721 else if ((urn[1] == '3') && (urn[1] == 'B'))
722 result[i++] = ';';
723 else if ((urn[1] == '2') && (urn[1] == '7'))
724 result[i++] = '\'';
725 else if ((urn[1] == '3') && (urn[1] == 'F'))
726 result[i++] = '?';
727 else if ((urn[1] == '2') && (urn[1] == '3'))
728 result[i++] = '#';
729 else if ((urn[1] == '2') && (urn[1] == '5'))
730 result[i++] = '%';
731 else {
732 result[i++] = *urn;
733 urn++;
734 continue;
735 }
736 urn += 3;
737 } else {
738 result[i++] = *urn;
739 urn++;
740 }
741 }
742 result[i] = 0;
743
744 return(xmlStrdup(result));
745}
746
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000747/**
748 * xmlParseCatalogFile:
749 * @filename: the filename
750 *
751 * parse an XML file and build a tree. It's like xmlParseFile()
752 * except it bypass all catalog lookups.
753 *
754 * Returns the resulting document tree or NULL in case of error
755 */
756
757xmlDocPtr
758xmlParseCatalogFile(const char *filename) {
759 xmlDocPtr ret;
760 xmlParserCtxtPtr ctxt;
761 char *directory = NULL;
762 xmlParserInputPtr inputStream;
763 xmlParserInputBufferPtr buf;
764
765 ctxt = xmlNewParserCtxt();
766 if (ctxt == NULL) {
767 if (xmlDefaultSAXHandler.error != NULL) {
768 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
769 }
770 return(NULL);
771 }
772
773 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
774 if (buf == NULL) {
775 xmlFreeParserCtxt(ctxt);
776 return(NULL);
777 }
778
779 inputStream = xmlNewInputStream(ctxt);
780 if (inputStream == NULL) {
781 xmlFreeParserCtxt(ctxt);
782 return(NULL);
783 }
784
785 inputStream->filename = xmlMemStrdup(filename);
786 inputStream->buf = buf;
787 inputStream->base = inputStream->buf->buffer->content;
788 inputStream->cur = inputStream->buf->buffer->content;
789 inputStream->end =
790 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
791
792 inputPush(ctxt, inputStream);
793 if ((ctxt->directory == NULL) && (directory == NULL))
794 directory = xmlParserGetDirectory(filename);
795 if ((ctxt->directory == NULL) && (directory != NULL))
796 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000797 ctxt->valid = 0;
798 ctxt->validate = 0;
799 ctxt->loadsubset = 0;
800 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000801
802 xmlParseDocument(ctxt);
803
804 if (ctxt->wellFormed)
805 ret = ctxt->myDoc;
806 else {
807 ret = NULL;
808 xmlFreeDoc(ctxt->myDoc);
809 ctxt->myDoc = NULL;
810 }
811 xmlFreeParserCtxt(ctxt);
812
813 return(ret);
814}
815
Daniel Veillard75b96822001-10-11 18:59:45 +0000816/**
817 * xmlLoadFileContent:
818 * @filename: a file path
819 *
820 * Load a file content into memory.
821 *
822 * Returns a pointer to the 0 terminated string or NULL in case of error
823 */
824static xmlChar *
825xmlLoadFileContent(const char *filename)
826{
827#ifdef HAVE_STAT
828 int fd;
829#else
830 FILE *fd;
831#endif
832 int len;
833 long size;
834
835#ifdef HAVE_STAT
836 struct stat info;
837#endif
838 xmlChar *content;
839
840 if (filename == NULL)
841 return (NULL);
842
843#ifdef HAVE_STAT
844 if (stat(filename, &info) < 0)
845 return (NULL);
846#endif
847
848#ifdef HAVE_STAT
849 if ((fd = open(filename, O_RDONLY)) < 0) {
850#else
851 if ((fd = fopen(filename, "rb")) == NULL) {
852#endif
853 return (NULL);
854 }
855#ifdef HAVE_STAT
856 size = info.st_size;
857#else
858 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
859 fclose(fd);
860 return (NULL);
861 }
862#endif
863 content = xmlMalloc(size + 10);
864 if (content == NULL) {
865 xmlGenericError(xmlGenericErrorContext,
866 "malloc of %d byte failed\n", size + 10);
867 return (NULL);
868 }
869#ifdef HAVE_STAT
870 len = read(fd, content, size);
871#else
872 len = fread(content, 1, size, fd);
873#endif
874 if (len < 0) {
875 xmlFree(content);
876 return (NULL);
877 }
878#ifdef HAVE_STAT
879 close(fd);
880#else
881 fclose(fd);
882#endif
883 content[len] = 0;
884
885 return(content);
886}
887
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000888/************************************************************************
889 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000890 * The XML Catalog parser *
891 * *
892 ************************************************************************/
893
894static xmlCatalogEntryPtr
895xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000896static void
897xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
898 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000899static xmlChar *
900xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
901 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000902static xmlChar *
903xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
904
Daniel Veillard344cee72001-08-20 00:08:40 +0000905
Daniel Veillard75b96822001-10-11 18:59:45 +0000906/**
907 * xmlGetXMLCatalogEntryType:
908 * @name: the name
909 *
910 * lookup the internal type associated to an XML catalog entry name
911 *
912 * Returns the type associate with that name
913 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000914static xmlCatalogEntryType
915xmlGetXMLCatalogEntryType(const xmlChar *name) {
916 xmlCatalogEntryType type = XML_CATA_NONE;
917 if (xmlStrEqual(name, (const xmlChar *) "system"))
918 type = XML_CATA_SYSTEM;
919 else if (xmlStrEqual(name, (const xmlChar *) "public"))
920 type = XML_CATA_PUBLIC;
921 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
922 type = XML_CATA_REWRITE_SYSTEM;
923 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
924 type = XML_CATA_DELEGATE_PUBLIC;
925 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
926 type = XML_CATA_DELEGATE_SYSTEM;
927 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
928 type = XML_CATA_URI;
929 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
930 type = XML_CATA_REWRITE_URI;
931 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
932 type = XML_CATA_DELEGATE_URI;
933 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
934 type = XML_CATA_NEXT_CATALOG;
935 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
936 type = XML_CATA_CATALOG;
937 return(type);
938}
939
Daniel Veillard75b96822001-10-11 18:59:45 +0000940/**
941 * xmlParseXMLCatalogOneNode:
942 * @cur: the XML node
943 * @type: the type of Catalog entry
944 * @name: the name of the node
945 * @attrName: the attribute holding the value
946 * @uriAttrName: the attribute holding the URI-Reference
947 * @prefer: the PUBLIC vs. SYSTEM current preference value
948 *
949 * Finishes the examination of an XML tree node of a catalog and build
950 * a Catalog entry from it.
951 *
952 * Returns the new Catalog entry node or NULL in case of error.
953 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000954static xmlCatalogEntryPtr
955xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
956 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000957 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000958 int ok = 1;
959 xmlChar *uriValue;
960 xmlChar *nameValue = NULL;
961 xmlChar *base = NULL;
962 xmlChar *URL = NULL;
963 xmlCatalogEntryPtr ret = NULL;
964
965 if (attrName != NULL) {
966 nameValue = xmlGetProp(cur, attrName);
967 if (nameValue == NULL) {
968 xmlGenericError(xmlGenericErrorContext,
969 "%s entry lacks '%s'\n", name, attrName);
970 ok = 0;
971 }
972 }
973 uriValue = xmlGetProp(cur, uriAttrName);
974 if (uriValue == NULL) {
975 xmlGenericError(xmlGenericErrorContext,
976 "%s entry lacks '%s'\n", name, uriAttrName);
977 ok = 0;
978 }
979 if (!ok) {
980 if (nameValue != NULL)
981 xmlFree(nameValue);
982 if (uriValue != NULL)
983 xmlFree(uriValue);
984 return(NULL);
985 }
986
987 base = xmlNodeGetBase(cur->doc, cur);
988 URL = xmlBuildURI(uriValue, base);
989 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000990 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000991 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000992 xmlGenericError(xmlGenericErrorContext,
993 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000994 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000995 xmlGenericError(xmlGenericErrorContext,
996 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000997 }
Daniel Veillardc853b322001-11-06 15:24:37 +0000998 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000999 } else {
1000 xmlGenericError(xmlGenericErrorContext,
1001 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1002 }
1003 if (nameValue != NULL)
1004 xmlFree(nameValue);
1005 if (uriValue != NULL)
1006 xmlFree(uriValue);
1007 if (base != NULL)
1008 xmlFree(base);
1009 if (URL != NULL)
1010 xmlFree(URL);
1011 return(ret);
1012}
1013
Daniel Veillard75b96822001-10-11 18:59:45 +00001014/**
1015 * xmlParseXMLCatalogNode:
1016 * @cur: the XML node
1017 * @prefer: the PUBLIC vs. SYSTEM current preference value
1018 * @parent: the parent Catalog entry
1019 *
1020 * Examines an XML tree node of a catalog and build
1021 * a Catalog entry from it adding it to its parent. The examination can
1022 * be recursive.
1023 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001024static void
1025xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1026 xmlCatalogEntryPtr parent)
1027{
1028 xmlChar *uri = NULL;
1029 xmlChar *URL = NULL;
1030 xmlChar *base = NULL;
1031 xmlCatalogEntryPtr entry = NULL;
1032
1033 if (cur == NULL)
1034 return;
1035 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1036 xmlChar *prop;
1037
1038 prop = xmlGetProp(cur, BAD_CAST "prefer");
1039 if (prop != NULL) {
1040 if (xmlStrEqual(prop, BAD_CAST "system")) {
1041 prefer = XML_CATA_PREFER_SYSTEM;
1042 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1043 prefer = XML_CATA_PREFER_PUBLIC;
1044 } else {
1045 xmlGenericError(xmlGenericErrorContext,
1046 "Invalid value for prefer: '%s'\n", prop);
1047 }
1048 xmlFree(prop);
1049 }
1050 /*
1051 * Recurse to propagate prefer to the subtree
1052 * (xml:base handling is automated)
1053 */
1054 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1055 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1056 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001057 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001058 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1059 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001060 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001061 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1062 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1063 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001064 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001065 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1066 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1067 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001068 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001069 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1070 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1071 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001072 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001073 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1074 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1075 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001076 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001077 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1078 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1079 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001080 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001081 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1082 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1083 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001084 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001085 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1086 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1087 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001088 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001089 }
1090 if ((entry != NULL) && (parent != NULL)) {
1091 entry->parent = parent;
1092 if (parent->children == NULL)
1093 parent->children = entry;
1094 else {
1095 xmlCatalogEntryPtr prev;
1096
1097 prev = parent->children;
1098 while (prev->next != NULL)
1099 prev = prev->next;
1100 prev->next = entry;
1101 }
1102 }
1103 if (base != NULL)
1104 xmlFree(base);
1105 if (uri != NULL)
1106 xmlFree(uri);
1107 if (URL != NULL)
1108 xmlFree(URL);
1109}
1110
Daniel Veillard75b96822001-10-11 18:59:45 +00001111/**
1112 * xmlParseXMLCatalogNodeList:
1113 * @cur: the XML node list of siblings
1114 * @prefer: the PUBLIC vs. SYSTEM current preference value
1115 * @parent: the parent Catalog entry
1116 *
1117 * Examines a list of XML sibling nodes of a catalog and build
1118 * a list of Catalog entry from it adding it to the parent.
1119 * The examination will recurse to examine node subtrees.
1120 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001121static void
1122xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1123 xmlCatalogEntryPtr parent) {
1124 while (cur != NULL) {
1125 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1126 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1127 xmlParseXMLCatalogNode(cur, prefer, parent);
1128 }
1129 cur = cur->next;
1130 }
1131 /* TODO: sort the list according to REWRITE lengths and prefer value */
1132}
1133
Daniel Veillard75b96822001-10-11 18:59:45 +00001134/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001135 * xmlParseXMLCatalogFile:
1136 * @prefer: the PUBLIC vs. SYSTEM current preference value
1137 * @filename: the filename for the catalog
1138 *
1139 * Parses the catalog file to extract the XML tree and then analyze the
1140 * tree to build a list of Catalog entries corresponding to this catalog
1141 *
1142 * Returns the resulting Catalog entries list
1143 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001144static xmlCatalogEntryPtr
1145xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1146 xmlDocPtr doc;
1147 xmlNodePtr cur;
1148 xmlChar *prop;
1149 xmlCatalogEntryPtr parent = NULL;
1150
1151 if (filename == NULL)
1152 return(NULL);
1153
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001154 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001155 if (doc == NULL) {
1156 if (xmlDebugCatalogs)
1157 xmlGenericError(xmlGenericErrorContext,
1158 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001159 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001160 }
1161
1162 if (xmlDebugCatalogs)
1163 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001164 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001165
1166 cur = xmlDocGetRootElement(doc);
1167 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1168 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1169 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1170
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001171 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00001172 (const xmlChar *)filename, NULL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001173 if (parent == NULL) {
1174 xmlFreeDoc(doc);
1175 return(NULL);
1176 }
1177
1178 prop = xmlGetProp(cur, BAD_CAST "prefer");
1179 if (prop != NULL) {
1180 if (xmlStrEqual(prop, BAD_CAST "system")) {
1181 prefer = XML_CATA_PREFER_SYSTEM;
1182 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1183 prefer = XML_CATA_PREFER_PUBLIC;
1184 } else {
1185 xmlGenericError(xmlGenericErrorContext,
1186 "Invalid value for prefer: '%s'\n",
1187 prop);
1188 }
1189 xmlFree(prop);
1190 }
1191 cur = cur->children;
1192 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1193 } else {
1194 xmlGenericError(xmlGenericErrorContext,
1195 "File %s is not an XML Catalog\n", filename);
1196 xmlFreeDoc(doc);
1197 return(NULL);
1198 }
1199 xmlFreeDoc(doc);
1200 return(parent);
1201}
1202
Daniel Veillardcda96922001-08-21 10:56:31 +00001203/**
1204 * xmlFetchXMLCatalogFile:
1205 * @catal: an existing but incomplete catalog entry
1206 *
1207 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001208 *
1209 * Returns 0 in case of success, -1 otherwise
1210 */
1211static int
1212xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001213 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001214
1215 if (catal == NULL)
1216 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001217 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001218 return(-1);
1219 if (catal->children != NULL)
1220 return(-1);
1221
Daniel Veillard81463942001-10-16 12:34:39 +00001222 /*
1223 * lock the whole catalog for modification
1224 */
1225 xmlRMutexLock(xmlCatalogMutex);
1226 if (catal->children != NULL) {
1227 /* Okay someone else did it in the meantime */
1228 xmlRMutexUnlock(xmlCatalogMutex);
1229 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001230 }
1231
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001232 if (xmlCatalogXMLFiles != NULL) {
1233 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001234 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001235 if (doc != NULL) {
1236 if (xmlDebugCatalogs)
1237 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001238 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001239
1240 if (catal->type == XML_CATA_CATALOG)
1241 catal->children = doc->children;
1242 else
1243 catal->children = doc;
1244 catal->dealloc = 0;
1245 xmlRMutexUnlock(xmlCatalogMutex);
1246 return(0);
1247 }
1248 if (xmlDebugCatalogs)
1249 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001250 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001251 }
1252
Daniel Veillardcda96922001-08-21 10:56:31 +00001253 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001254 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001255 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001256 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001257 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001258 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001259 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001260 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001261 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001262 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001263 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001264
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001265 if (catal->type == XML_CATA_CATALOG)
1266 catal->children = doc->children;
1267 else
1268 catal->children = doc;
1269
1270 doc->dealloc = 1;
1271
Daniel Veillard81463942001-10-16 12:34:39 +00001272 if (xmlCatalogXMLFiles == NULL)
1273 xmlCatalogXMLFiles = xmlHashCreate(10);
1274 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001275 if (xmlDebugCatalogs)
1276 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001277 "%s added to file hash\n", catal->URL);
1278 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001279 }
Daniel Veillard81463942001-10-16 12:34:39 +00001280 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001281 return(0);
1282}
1283
Daniel Veillard75b96822001-10-11 18:59:45 +00001284/************************************************************************
1285 * *
1286 * XML Catalog handling *
1287 * *
1288 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001289
1290/**
1291 * xmlAddXMLCatalog:
1292 * @catal: top of an XML catalog
1293 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001294 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001295 * @replace: the replacement value for the match
1296 *
1297 * Add an entry in the XML catalog, it may overwrite existing but
1298 * different entries.
1299 *
1300 * Returns 0 if successful, -1 otherwise
1301 */
1302static int
1303xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1304 const xmlChar *orig, const xmlChar *replace) {
1305 xmlCatalogEntryPtr cur;
1306 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001307 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001308
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001309 if ((catal == NULL) ||
1310 ((catal->type != XML_CATA_CATALOG) &&
1311 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001312 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001313 if (catal->children == NULL) {
1314 xmlFetchXMLCatalogFile(catal);
1315 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001316 if (catal->children == NULL)
1317 doregister = 1;
1318
Daniel Veillard344cee72001-08-20 00:08:40 +00001319 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001320 if (typ == XML_CATA_NONE) {
1321 if (xmlDebugCatalogs)
1322 xmlGenericError(xmlGenericErrorContext,
1323 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001324 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001325 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001326
1327 cur = catal->children;
1328 /*
1329 * Might be a simple "update in place"
1330 */
1331 if (cur != NULL) {
1332 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001333 if ((orig != NULL) && (cur->type == typ) &&
1334 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001335 if (xmlDebugCatalogs)
1336 xmlGenericError(xmlGenericErrorContext,
1337 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001338 if (cur->value != NULL)
1339 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001340 if (cur->URL != NULL)
1341 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001342 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001343 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001344 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001345 }
1346 if (cur->next == NULL)
1347 break;
1348 cur = cur->next;
1349 }
1350 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001351 if (xmlDebugCatalogs)
1352 xmlGenericError(xmlGenericErrorContext,
1353 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001354 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001355 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1356 NULL, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001357 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001358 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1359 NULL, catal->prefer);
1360 if (doregister) {
1361 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1362 if (cur != NULL)
1363 cur->children = catal->children;
1364 }
1365
Daniel Veillardcda96922001-08-21 10:56:31 +00001366 return(0);
1367}
1368
1369/**
1370 * xmlDelXMLCatalog:
1371 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001372 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001373 *
1374 * Remove entries in the XML catalog where the value or the URI
1375 * is equal to @value
1376 *
1377 * Returns the number of entries removed if successful, -1 otherwise
1378 */
1379static int
1380xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001381 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001382 int ret = 0;
1383
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001384 if ((catal == NULL) ||
1385 ((catal->type != XML_CATA_CATALOG) &&
1386 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001387 return(-1);
1388 if (value == NULL)
1389 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001390 if (catal->children == NULL) {
1391 xmlFetchXMLCatalogFile(catal);
1392 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001393
1394 /*
1395 * Scan the children
1396 */
1397 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001398 while (cur != NULL) {
1399 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1400 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001401 if (xmlDebugCatalogs) {
1402 if (cur->name != NULL)
1403 xmlGenericError(xmlGenericErrorContext,
1404 "Removing element %s from catalog\n", cur->name);
1405 else
1406 xmlGenericError(xmlGenericErrorContext,
1407 "Removing element %s from catalog\n", cur->value);
1408 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001409 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001410 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001411 cur = cur->next;
1412 }
1413 return(ret);
1414}
1415
1416/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001417 * xmlCatalogXMLResolve:
1418 * @catal: a catalog list
1419 * @pubId: the public ID string
1420 * @sysId: the system ID string
1421 *
1422 * Do a complete resolution lookup of an External Identifier for a
1423 * list of catalog entries.
1424 *
1425 * Implements (or tries to) 7.1. External Identifier Resolution
1426 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1427 *
1428 * Returns the URI of the resource or NULL if not found
1429 */
1430static xmlChar *
1431xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1432 const xmlChar *sysID) {
1433 xmlChar *ret = NULL;
1434 xmlCatalogEntryPtr cur;
1435 int haveDelegate = 0;
1436 int haveNext = 0;
1437
1438 /*
1439 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1440 */
1441 if (sysID != NULL) {
1442 xmlCatalogEntryPtr rewrite = NULL;
1443 int lenrewrite = 0, len;
1444 cur = catal;
1445 haveDelegate = 0;
1446 while (cur != NULL) {
1447 switch (cur->type) {
1448 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001449 if (xmlStrEqual(sysID, cur->name)) {
1450 if (xmlDebugCatalogs)
1451 xmlGenericError(xmlGenericErrorContext,
1452 "Found system match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001453 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001454 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001455 break;
1456 case XML_CATA_REWRITE_SYSTEM:
1457 len = xmlStrlen(cur->name);
1458 if ((len > lenrewrite) &&
1459 (!xmlStrncmp(sysID, cur->name, len))) {
1460 lenrewrite = len;
1461 rewrite = cur;
1462 }
1463 break;
1464 case XML_CATA_DELEGATE_SYSTEM:
1465 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1466 haveDelegate++;
1467 break;
1468 case XML_CATA_NEXT_CATALOG:
1469 haveNext++;
1470 break;
1471 default:
1472 break;
1473 }
1474 cur = cur->next;
1475 }
1476 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001477 if (xmlDebugCatalogs)
1478 xmlGenericError(xmlGenericErrorContext,
1479 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001480 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001481 if (ret != NULL)
1482 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1483 return(ret);
1484 }
1485 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001486 const xmlChar *delegates[MAX_DELEGATE];
1487 int nbList = 0, i;
1488
Daniel Veillardcda96922001-08-21 10:56:31 +00001489 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001490 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001491 * matches when the list was produced.
1492 */
1493 cur = catal;
1494 while (cur != NULL) {
1495 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1496 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001497 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001498 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001499 break;
1500 if (i < nbList) {
1501 cur = cur->next;
1502 continue;
1503 }
1504 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001505 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001506
Daniel Veillardcda96922001-08-21 10:56:31 +00001507 if (cur->children == NULL) {
1508 xmlFetchXMLCatalogFile(cur);
1509 }
1510 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001511 if (xmlDebugCatalogs)
1512 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001513 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001514 ret = xmlCatalogListXMLResolve(
1515 cur->children, NULL, sysID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001516 if (ret != NULL)
1517 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001518 }
1519 }
1520 cur = cur->next;
1521 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001522 /*
1523 * Apply the cut algorithm explained in 4/
1524 */
1525 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001526 }
1527 }
1528 /*
1529 * Then tries 5/ 6/ if a public ID is provided
1530 */
1531 if (pubID != NULL) {
1532 cur = catal;
1533 haveDelegate = 0;
1534 while (cur != NULL) {
1535 switch (cur->type) {
1536 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001537 if (xmlStrEqual(pubID, cur->name)) {
1538 if (xmlDebugCatalogs)
1539 xmlGenericError(xmlGenericErrorContext,
1540 "Found public match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001541 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001542 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001543 break;
1544 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001545 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1546 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001547 haveDelegate++;
1548 break;
1549 case XML_CATA_NEXT_CATALOG:
1550 if (sysID == NULL)
1551 haveNext++;
1552 break;
1553 default:
1554 break;
1555 }
1556 cur = cur->next;
1557 }
1558 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001559 const xmlChar *delegates[MAX_DELEGATE];
1560 int nbList = 0, i;
1561
Daniel Veillardcda96922001-08-21 10:56:31 +00001562 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001563 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001564 * matches when the list was produced.
1565 */
1566 cur = catal;
1567 while (cur != NULL) {
1568 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001569 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1570 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001571
1572 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001573 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001574 break;
1575 if (i < nbList) {
1576 cur = cur->next;
1577 continue;
1578 }
1579 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001580 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001581
Daniel Veillardcda96922001-08-21 10:56:31 +00001582 if (cur->children == NULL) {
1583 xmlFetchXMLCatalogFile(cur);
1584 }
1585 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001586 if (xmlDebugCatalogs)
1587 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001588 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001589 ret = xmlCatalogListXMLResolve(
1590 cur->children, pubID, NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001591 if (ret != NULL)
1592 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001593 }
1594 }
1595 cur = cur->next;
1596 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001597 /*
1598 * Apply the cut algorithm explained in 4/
1599 */
1600 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001601 }
1602 }
1603 if (haveNext) {
1604 cur = catal;
1605 while (cur != NULL) {
1606 if (cur->type == XML_CATA_NEXT_CATALOG) {
1607 if (cur->children == NULL) {
1608 xmlFetchXMLCatalogFile(cur);
1609 }
1610 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001611 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1612 if (ret != NULL)
1613 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001614 }
1615 }
1616 cur = cur->next;
1617 }
1618 }
1619
1620 return(NULL);
1621}
1622
1623/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001624 * xmlCatalogXMLResolveURI:
1625 * @catal: a catalog list
1626 * @URI: the URI
1627 * @sysId: the system ID string
1628 *
1629 * Do a complete resolution lookup of an External Identifier for a
1630 * list of catalog entries.
1631 *
1632 * Implements (or tries to) 7.2.2. URI Resolution
1633 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1634 *
1635 * Returns the URI of the resource or NULL if not found
1636 */
1637static xmlChar *
1638xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1639 xmlChar *ret = NULL;
1640 xmlCatalogEntryPtr cur;
1641 int haveDelegate = 0;
1642 int haveNext = 0;
1643 xmlCatalogEntryPtr rewrite = NULL;
1644 int lenrewrite = 0, len;
1645
1646 if (catal == NULL)
1647 return(NULL);
1648
1649 if (URI == NULL)
1650 return(NULL);
1651
1652 /*
1653 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1654 */
1655 cur = catal;
1656 haveDelegate = 0;
1657 while (cur != NULL) {
1658 switch (cur->type) {
1659 case XML_CATA_URI:
1660 if (xmlStrEqual(URI, cur->name)) {
1661 if (xmlDebugCatalogs)
1662 xmlGenericError(xmlGenericErrorContext,
1663 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001664 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001665 }
1666 break;
1667 case XML_CATA_REWRITE_URI:
1668 len = xmlStrlen(cur->name);
1669 if ((len > lenrewrite) &&
1670 (!xmlStrncmp(URI, cur->name, len))) {
1671 lenrewrite = len;
1672 rewrite = cur;
1673 }
1674 break;
1675 case XML_CATA_DELEGATE_URI:
1676 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1677 haveDelegate++;
1678 break;
1679 case XML_CATA_NEXT_CATALOG:
1680 haveNext++;
1681 break;
1682 default:
1683 break;
1684 }
1685 cur = cur->next;
1686 }
1687 if (rewrite != NULL) {
1688 if (xmlDebugCatalogs)
1689 xmlGenericError(xmlGenericErrorContext,
1690 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001691 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001692 if (ret != NULL)
1693 ret = xmlStrcat(ret, &URI[lenrewrite]);
1694 return(ret);
1695 }
1696 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001697 const xmlChar *delegates[MAX_DELEGATE];
1698 int nbList = 0, i;
1699
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001700 /*
1701 * Assume the entries have been sorted by decreasing substring
1702 * matches when the list was produced.
1703 */
1704 cur = catal;
1705 while (cur != NULL) {
1706 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1707 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001708 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001709 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001710 break;
1711 if (i < nbList) {
1712 cur = cur->next;
1713 continue;
1714 }
1715 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001716 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001717
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001718 if (cur->children == NULL) {
1719 xmlFetchXMLCatalogFile(cur);
1720 }
1721 if (cur->children != NULL) {
1722 if (xmlDebugCatalogs)
1723 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001724 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001725 ret = xmlCatalogListXMLResolveURI(
1726 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001727 if (ret != NULL)
1728 return(ret);
1729 }
1730 }
1731 cur = cur->next;
1732 }
1733 /*
1734 * Apply the cut algorithm explained in 4/
1735 */
1736 return(XML_CATAL_BREAK);
1737 }
1738 if (haveNext) {
1739 cur = catal;
1740 while (cur != NULL) {
1741 if (cur->type == XML_CATA_NEXT_CATALOG) {
1742 if (cur->children == NULL) {
1743 xmlFetchXMLCatalogFile(cur);
1744 }
1745 if (cur->children != NULL) {
1746 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1747 if (ret != NULL)
1748 return(ret);
1749 }
1750 }
1751 cur = cur->next;
1752 }
1753 }
1754
1755 return(NULL);
1756}
1757
1758/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001759 * xmlCatalogListXMLResolve:
1760 * @catal: a catalog list
1761 * @pubId: the public ID string
1762 * @sysId: the system ID string
1763 *
1764 * Do a complete resolution lookup of an External Identifier for a
1765 * list of catalogs
1766 *
1767 * Implements (or tries to) 7.1. External Identifier Resolution
1768 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1769 *
1770 * Returns the URI of the resource or NULL if not found
1771 */
1772static xmlChar *
1773xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1774 const xmlChar *sysID) {
1775 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001776 xmlChar *urnID = NULL;
1777
1778 if (catal == NULL)
1779 return(NULL);
1780 if ((pubID == NULL) && (sysID == NULL))
1781 return(NULL);
1782
1783 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1784 urnID = xmlCatalogUnWrapURN(pubID);
1785 if (xmlDebugCatalogs) {
1786 if (urnID == NULL)
1787 xmlGenericError(xmlGenericErrorContext,
1788 "Public URN ID %s expanded to NULL\n", pubID);
1789 else
1790 xmlGenericError(xmlGenericErrorContext,
1791 "Public URN ID expanded to %s\n", urnID);
1792 }
1793 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1794 if (urnID != NULL)
1795 xmlFree(urnID);
1796 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001797 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001798 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1799 urnID = xmlCatalogUnWrapURN(sysID);
1800 if (xmlDebugCatalogs) {
1801 if (urnID == NULL)
1802 xmlGenericError(xmlGenericErrorContext,
1803 "System URN ID %s expanded to NULL\n", sysID);
1804 else
1805 xmlGenericError(xmlGenericErrorContext,
1806 "System URN ID expanded to %s\n", urnID);
1807 }
1808 if (pubID == NULL)
1809 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1810 else if (xmlStrEqual(pubID, urnID))
1811 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1812 else {
1813 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1814 }
1815 if (urnID != NULL)
1816 xmlFree(urnID);
1817 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001818 }
1819 while (catal != NULL) {
1820 if (catal->type == XML_CATA_CATALOG) {
1821 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001822 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001823 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001824 if (catal->children != NULL) {
1825 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1826 if (ret != NULL)
1827 return(ret);
1828 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001829 }
1830 catal = catal->next;
1831 }
1832 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001833}
1834
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001835/**
1836 * xmlCatalogListXMLResolveURI:
1837 * @catal: a catalog list
1838 * @URI: the URI
1839 *
1840 * Do a complete resolution lookup of an URI for a list of catalogs
1841 *
1842 * Implements (or tries to) 7.2. URI Resolution
1843 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1844 *
1845 * Returns the URI of the resource or NULL if not found
1846 */
1847static xmlChar *
1848xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1849 xmlChar *ret = NULL;
1850 xmlChar *urnID = NULL;
1851
1852 if (catal == NULL)
1853 return(NULL);
1854 if (URI == NULL)
1855 return(NULL);
1856
1857 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1858 urnID = xmlCatalogUnWrapURN(URI);
1859 if (xmlDebugCatalogs) {
1860 if (urnID == NULL)
1861 xmlGenericError(xmlGenericErrorContext,
1862 "URN ID %s expanded to NULL\n", URI);
1863 else
1864 xmlGenericError(xmlGenericErrorContext,
1865 "URN ID expanded to %s\n", urnID);
1866 }
1867 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1868 if (urnID != NULL)
1869 xmlFree(urnID);
1870 return(ret);
1871 }
1872 while (catal != NULL) {
1873 if (catal->type == XML_CATA_CATALOG) {
1874 if (catal->children == NULL) {
1875 xmlFetchXMLCatalogFile(catal);
1876 }
1877 if (catal->children != NULL) {
1878 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1879 if (ret != NULL)
1880 return(ret);
1881 }
1882 }
1883 catal = catal->next;
1884 }
1885 return(ret);
1886}
1887
Daniel Veillard344cee72001-08-20 00:08:40 +00001888/************************************************************************
1889 * *
1890 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001891 * *
1892 ************************************************************************/
1893
1894
1895#define RAW *cur
1896#define NEXT cur++;
1897#define SKIP(x) cur += x;
1898
1899#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1900
Daniel Veillard75b96822001-10-11 18:59:45 +00001901/**
1902 * xmlParseSGMLCatalogComment:
1903 * @cur: the current character
1904 *
1905 * Skip a comment in an SGML catalog
1906 *
1907 * Returns new current character
1908 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001909static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001910xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001911 if ((cur[0] != '-') || (cur[1] != '-'))
1912 return(cur);
1913 SKIP(2);
1914 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1915 NEXT;
1916 if (cur[0] == 0) {
1917 return(NULL);
1918 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001919 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001920}
1921
Daniel Veillard75b96822001-10-11 18:59:45 +00001922/**
1923 * xmlParseSGMLCatalogPubid:
1924 * @cur: the current character
1925 * @id: the return location
1926 *
1927 * Parse an SGML catalog ID
1928 *
1929 * Returns new current character and store the value in @id
1930 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001931static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001932xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001933 xmlChar *buf = NULL;
1934 int len = 0;
1935 int size = 50;
1936 xmlChar stop;
1937 int count = 0;
1938
1939 *id = NULL;
1940
1941 if (RAW == '"') {
1942 NEXT;
1943 stop = '"';
1944 } else if (RAW == '\'') {
1945 NEXT;
1946 stop = '\'';
1947 } else {
1948 stop = ' ';
1949 }
1950 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1951 if (buf == NULL) {
1952 xmlGenericError(xmlGenericErrorContext,
1953 "malloc of %d byte failed\n", size);
1954 return(NULL);
1955 }
1956 while (xmlIsPubidChar(*cur)) {
1957 if ((*cur == stop) && (stop != ' '))
1958 break;
1959 if ((stop == ' ') && (IS_BLANK(*cur)))
1960 break;
1961 if (len + 1 >= size) {
1962 size *= 2;
1963 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1964 if (buf == NULL) {
1965 xmlGenericError(xmlGenericErrorContext,
1966 "realloc of %d byte failed\n", size);
1967 return(NULL);
1968 }
1969 }
1970 buf[len++] = *cur;
1971 count++;
1972 NEXT;
1973 }
1974 buf[len] = 0;
1975 if (stop == ' ') {
1976 if (!IS_BLANK(*cur)) {
1977 xmlFree(buf);
1978 return(NULL);
1979 }
1980 } else {
1981 if (*cur != stop) {
1982 xmlFree(buf);
1983 return(NULL);
1984 }
1985 NEXT;
1986 }
1987 *id = buf;
1988 return(cur);
1989}
1990
Daniel Veillard75b96822001-10-11 18:59:45 +00001991/**
1992 * xmlParseSGMLCatalogName:
1993 * @cur: the current character
1994 * @name: the return location
1995 *
1996 * Parse an SGML catalog name
1997 *
1998 * Returns new current character and store the value in @name
1999 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002000static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002001xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002002 xmlChar buf[XML_MAX_NAMELEN + 5];
2003 int len = 0;
2004 int c;
2005
2006 *name = NULL;
2007
2008 /*
2009 * Handler for more complex cases
2010 */
2011 c = *cur;
2012 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2013 return(NULL);
2014 }
2015
2016 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2017 (c == '.') || (c == '-') ||
2018 (c == '_') || (c == ':'))) {
2019 buf[len++] = c;
2020 cur++;
2021 c = *cur;
2022 if (len >= XML_MAX_NAMELEN)
2023 return(NULL);
2024 }
2025 *name = xmlStrndup(buf, len);
2026 return(cur);
2027}
2028
Daniel Veillard75b96822001-10-11 18:59:45 +00002029/**
2030 * xmlGetSGMLCatalogEntryType:
2031 * @name: the entry name
2032 *
2033 * Get the Catalog entry type for a given SGML Catalog name
2034 *
2035 * Returns Catalog entry type
2036 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002037static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002038xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002039 xmlCatalogEntryType type = XML_CATA_NONE;
2040 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2041 type = SGML_CATA_SYSTEM;
2042 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2043 type = SGML_CATA_PUBLIC;
2044 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2045 type = SGML_CATA_DELEGATE;
2046 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2047 type = SGML_CATA_ENTITY;
2048 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2049 type = SGML_CATA_DOCTYPE;
2050 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2051 type = SGML_CATA_LINKTYPE;
2052 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2053 type = SGML_CATA_NOTATION;
2054 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2055 type = SGML_CATA_SGMLDECL;
2056 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2057 type = SGML_CATA_DOCUMENT;
2058 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2059 type = SGML_CATA_CATALOG;
2060 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2061 type = SGML_CATA_BASE;
2062 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2063 type = SGML_CATA_DELEGATE;
2064 return(type);
2065}
2066
Daniel Veillard75b96822001-10-11 18:59:45 +00002067/**
2068 * xmlParseSGMLCatalog:
2069 * @catal: the SGML Catalog
2070 * @value: the content of the SGML Catalog serialization
2071 * @file: the filepath for the catalog
2072 * @super: should this be handled as a Super Catalog in which case
2073 * parsing is not recursive
2074 *
2075 * Parse an SGML catalog content and fill up the @catal hash table with
2076 * the new entries found.
2077 *
2078 * Returns 0 in case of success, -1 in case of error.
2079 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002080static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002081xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2082 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002083 const xmlChar *cur = value;
2084 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002085 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002086
2087 if ((cur == NULL) || (file == NULL))
2088 return(-1);
2089 base = xmlStrdup((const xmlChar *) file);
2090
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002091 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002092 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002093 if (cur[0] == 0)
2094 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002095 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002096 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002097 if (cur == NULL) {
2098 /* error */
2099 break;
2100 }
2101 } else {
2102 xmlChar *sysid = NULL;
2103 xmlChar *name = NULL;
2104 xmlCatalogEntryType type = XML_CATA_NONE;
2105
Daniel Veillardcda96922001-08-21 10:56:31 +00002106 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002107 if (name == NULL) {
2108 /* error */
2109 break;
2110 }
2111 if (!IS_BLANK(*cur)) {
2112 /* error */
2113 break;
2114 }
2115 SKIP_BLANKS;
2116 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002117 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002118 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002119 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002120 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002121 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002122 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002123 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002124 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002125 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002126 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002127 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002128 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002129 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002130 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002131 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002132 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002133 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002134 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002135 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002136 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002137 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002138 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002139 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002140 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2141 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002142 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002143 if (name == NULL) {
2144 /* error */
2145 break;
2146 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002147 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002148 continue;
2149 }
2150 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002151 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002152
2153 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002154 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002155 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002156 type = SGML_CATA_PENTITY;
2157 case SGML_CATA_PENTITY:
2158 case SGML_CATA_DOCTYPE:
2159 case SGML_CATA_LINKTYPE:
2160 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002161 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002162 if (cur == NULL) {
2163 /* error */
2164 break;
2165 }
2166 if (!IS_BLANK(*cur)) {
2167 /* error */
2168 break;
2169 }
2170 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002171 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002172 if (cur == NULL) {
2173 /* error */
2174 break;
2175 }
2176 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002177 case SGML_CATA_PUBLIC:
2178 case SGML_CATA_SYSTEM:
2179 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002180 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002181 if (cur == NULL) {
2182 /* error */
2183 break;
2184 }
2185 if (!IS_BLANK(*cur)) {
2186 /* error */
2187 break;
2188 }
2189 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002190 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002191 if (cur == NULL) {
2192 /* error */
2193 break;
2194 }
2195 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002196 case SGML_CATA_BASE:
2197 case SGML_CATA_CATALOG:
2198 case SGML_CATA_DOCUMENT:
2199 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002200 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002201 if (cur == NULL) {
2202 /* error */
2203 break;
2204 }
2205 break;
2206 default:
2207 break;
2208 }
2209 if (cur == NULL) {
2210 if (name != NULL)
2211 xmlFree(name);
2212 if (sysid != NULL)
2213 xmlFree(sysid);
2214 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002215 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002216 if (base != NULL)
2217 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002218 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002219 } else if ((type == SGML_CATA_PUBLIC) ||
2220 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002221 xmlChar *filename;
2222
2223 filename = xmlBuildURI(sysid, base);
2224 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002225 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002226
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002227 entry = xmlNewCatalogEntry(type, name, filename,
Daniel Veillardc853b322001-11-06 15:24:37 +00002228 NULL, XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002229 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002230 if (res < 0) {
2231 xmlFreeCatalogEntry(entry);
2232 }
2233 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002234 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002235
Daniel Veillard344cee72001-08-20 00:08:40 +00002236 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002237 if (super) {
2238 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002239
Daniel Veillardc853b322001-11-06 15:24:37 +00002240 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
Daniel Veillard82d75332001-10-08 15:01:59 +00002241 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002242 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002243 if (res < 0) {
2244 xmlFreeCatalogEntry(entry);
2245 }
2246 } else {
2247 xmlChar *filename;
2248
2249 filename = xmlBuildURI(sysid, base);
2250 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002251 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002252 xmlFree(filename);
2253 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002254 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002255 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002256 /*
2257 * drop anything else we won't handle it
2258 */
2259 if (name != NULL)
2260 xmlFree(name);
2261 if (sysid != NULL)
2262 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002263 }
2264 }
2265 if (base != NULL)
2266 xmlFree(base);
2267 if (cur == NULL)
2268 return(-1);
2269 return(0);
2270}
2271
Daniel Veillard75b96822001-10-11 18:59:45 +00002272/************************************************************************
2273 * *
2274 * SGML Catalog handling *
2275 * *
2276 ************************************************************************/
2277
Daniel Veillardcda96922001-08-21 10:56:31 +00002278/**
2279 * xmlCatalogGetSGMLPublic:
2280 * @catal: an SGML catalog hash
2281 * @pubId: the public ID string
2282 *
2283 * Try to lookup the system ID associated to a public ID
2284 *
2285 * Returns the system ID if found or NULL otherwise.
2286 */
2287static const xmlChar *
2288xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2289 xmlCatalogEntryPtr entry;
2290
2291 if (catal == NULL)
2292 return(NULL);
2293
2294 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2295 if (entry == NULL)
2296 return(NULL);
2297 if (entry->type == SGML_CATA_PUBLIC)
Daniel Veillardc853b322001-11-06 15:24:37 +00002298 return(entry->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002299 return(NULL);
2300}
2301
2302/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002303 * xmlCatalogGetSGMLSystem:
2304 * @catal: an SGML catalog hash
2305 * @sysId: the public ID string
2306 *
2307 * Try to lookup the catalog local reference for a system ID
2308 *
2309 * Returns the system ID if found or NULL otherwise.
2310 */
2311static const xmlChar *
2312xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2313 xmlCatalogEntryPtr entry;
2314
2315 if (catal == NULL)
2316 return(NULL);
2317
2318 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2319 if (entry == NULL)
2320 return(NULL);
2321 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002322 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002323 return(NULL);
2324}
2325
2326/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002327 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002328 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002329 * @pubId: the public ID string
2330 * @sysId: the system ID string
2331 *
2332 * Do a complete resolution lookup of an External Identifier
2333 *
2334 * Returns the URI of the resource or NULL if not found
2335 */
2336static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002337xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2338 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002339 const xmlChar *ret = NULL;
2340
Daniel Veillard75b96822001-10-11 18:59:45 +00002341 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002342 return(NULL);
2343
2344 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002345 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002346 if (ret != NULL)
2347 return(ret);
2348 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002349 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002350 return(NULL);
2351}
2352
Daniel Veillarda7374592001-05-10 14:17:55 +00002353/************************************************************************
2354 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002355 * Specific Public interfaces *
2356 * *
2357 ************************************************************************/
2358
2359/**
2360 * xmlLoadSGMLSuperCatalog:
2361 * @filename: a file path
2362 *
2363 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2364 * references. This is only needed for manipulating SGML Super Catalogs
2365 * like adding and removing CATALOG or DELEGATE entries.
2366 *
2367 * Returns the catalog parsed or NULL in case of error
2368 */
2369xmlCatalogPtr
2370xmlLoadSGMLSuperCatalog(const char *filename)
2371{
2372 xmlChar *content;
2373 xmlCatalogPtr catal;
2374 int ret;
2375
2376 content = xmlLoadFileContent(filename);
2377 if (content == NULL)
2378 return(NULL);
2379
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002380 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002381 if (catal == NULL) {
2382 xmlFree(content);
2383 return(NULL);
2384 }
2385
2386 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2387 xmlFree(content);
2388 if (ret < 0) {
2389 xmlFreeCatalog(catal);
2390 return(NULL);
2391 }
2392 return (catal);
2393}
2394
2395/**
2396 * xmlLoadACatalog:
2397 * @filename: a file path
2398 *
2399 * Load the catalog and build the associated data structures.
2400 * This can be either an XML Catalog or an SGML Catalog
2401 * It will recurse in SGML CATALOG entries. On the other hand XML
2402 * Catalogs are not handled recursively.
2403 *
2404 * Returns the catalog parsed or NULL in case of error
2405 */
2406xmlCatalogPtr
2407xmlLoadACatalog(const char *filename)
2408{
2409 xmlChar *content;
2410 xmlChar *first;
2411 xmlCatalogPtr catal;
2412 int ret;
2413
2414 content = xmlLoadFileContent(filename);
2415 if (content == NULL)
2416 return(NULL);
2417
2418
2419 first = content;
2420
2421 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2422 (!(((*first >= 'A') && (*first <= 'Z')) ||
2423 ((*first >= 'a') && (*first <= 'z')))))
2424 first++;
2425
2426 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002427 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002428 if (catal == NULL) {
2429 xmlFree(content);
2430 return(NULL);
2431 }
2432 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2433 if (ret < 0) {
2434 xmlFreeCatalog(catal);
2435 xmlFree(content);
2436 return(NULL);
2437 }
2438 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002439 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002440 if (catal == NULL) {
2441 xmlFree(content);
2442 return(NULL);
2443 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002444 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002445 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002446 }
2447 xmlFree(content);
2448 return (catal);
2449}
2450
2451/**
2452 * xmlExpandCatalog:
2453 * @catal: a catalog
2454 * @filename: a file path
2455 *
2456 * Load the catalog and expand the existing catal structure.
2457 * This can be either an XML Catalog or an SGML Catalog
2458 *
2459 * Returns 0 in case of success, -1 in case of error
2460 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002461static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002462xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2463{
Daniel Veillard75b96822001-10-11 18:59:45 +00002464 int ret;
2465
2466 if ((catal == NULL) || (filename == NULL))
2467 return(-1);
2468
Daniel Veillard75b96822001-10-11 18:59:45 +00002469
2470 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002471 xmlChar *content;
2472
2473 content = xmlLoadFileContent(filename);
2474 if (content == NULL)
2475 return(-1);
2476
Daniel Veillard75b96822001-10-11 18:59:45 +00002477 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2478 if (ret < 0) {
2479 xmlFree(content);
2480 return(-1);
2481 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002482 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002483 } else {
2484 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002485 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002486 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002487
Daniel Veillard75b96822001-10-11 18:59:45 +00002488 cur = catal->xml;
2489 if (cur == NULL) {
2490 catal->xml = tmp;
2491 } else {
2492 while (cur->next != NULL) cur = cur->next;
2493 cur->next = tmp;
2494 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002495 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002496 return (0);
2497}
2498
2499/**
2500 * xmlACatalogResolveSystem:
2501 * @catal: a Catalog
2502 * @sysId: the public ID string
2503 *
2504 * Try to lookup the catalog resource for a system ID
2505 *
2506 * Returns the system ID if found or NULL otherwise, the value returned
2507 * must be freed by the caller.
2508 */
2509xmlChar *
2510xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2511 xmlChar *ret = NULL;
2512
2513 if ((sysID == NULL) || (catal == NULL))
2514 return(NULL);
2515
2516 if (xmlDebugCatalogs)
2517 xmlGenericError(xmlGenericErrorContext,
2518 "Resolve sysID %s\n", sysID);
2519
2520 if (catal->type == XML_XML_CATALOG_TYPE) {
2521 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2522 if (ret == XML_CATAL_BREAK)
2523 ret = NULL;
2524 } else {
2525 const xmlChar *sgml;
2526
2527 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2528 if (sgml != NULL)
2529 ret = xmlStrdup(sgml);
2530 }
2531 return(ret);
2532}
2533
2534/**
2535 * xmlACatalogResolvePublic:
2536 * @catal: a Catalog
2537 * @pubId: the public ID string
2538 *
2539 * Try to lookup the system ID associated to a public ID in that catalog
2540 *
2541 * Returns the system ID if found or NULL otherwise, the value returned
2542 * must be freed by the caller.
2543 */
2544xmlChar *
2545xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2546 xmlChar *ret = NULL;
2547
2548 if ((pubID == NULL) || (catal == NULL))
2549 return(NULL);
2550
2551 if (xmlDebugCatalogs)
2552 xmlGenericError(xmlGenericErrorContext,
2553 "Resolve pubID %s\n", pubID);
2554
2555 if (catal->type == XML_XML_CATALOG_TYPE) {
2556 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2557 if (ret == XML_CATAL_BREAK)
2558 ret = NULL;
2559 } else {
2560 const xmlChar *sgml;
2561
2562 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2563 if (sgml != NULL)
2564 ret = xmlStrdup(sgml);
2565 }
2566 return(ret);
2567}
2568
2569/**
2570 * xmlACatalogResolve:
2571 * @catal: a Catalog
2572 * @pubId: the public ID string
2573 * @sysId: the system ID string
2574 *
2575 * Do a complete resolution lookup of an External Identifier
2576 *
2577 * Returns the URI of the resource or NULL if not found, it must be freed
2578 * by the caller.
2579 */
2580xmlChar *
2581xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2582 const xmlChar * sysID)
2583{
2584 xmlChar *ret = NULL;
2585
2586 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2587 return (NULL);
2588
2589 if (xmlDebugCatalogs) {
2590 if (pubID != NULL) {
2591 xmlGenericError(xmlGenericErrorContext,
2592 "Resolve: pubID %s\n", pubID);
2593 } else {
2594 xmlGenericError(xmlGenericErrorContext,
2595 "Resolve: sysID %s\n", sysID);
2596 }
2597 }
2598
2599 if (catal->type == XML_XML_CATALOG_TYPE) {
2600 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2601 if (ret == XML_CATAL_BREAK)
2602 ret = NULL;
2603 } else {
2604 const xmlChar *sgml;
2605
2606 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2607 if (sgml != NULL)
2608 ret = xmlStrdup(sgml);
2609 }
2610 return (ret);
2611}
2612
2613/**
2614 * xmlACatalogResolveURI:
2615 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002616 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002617 *
2618 * Do a complete resolution lookup of an URI
2619 *
2620 * Returns the URI of the resource or NULL if not found, it must be freed
2621 * by the caller.
2622 */
2623xmlChar *
2624xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2625 xmlChar *ret = NULL;
2626
2627 if ((URI == NULL) || (catal == NULL))
2628 return(NULL);
2629
Daniel Veillardb44025c2001-10-11 22:55:55 +00002630 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002631 xmlGenericError(xmlGenericErrorContext,
2632 "Resolve URI %s\n", URI);
2633
2634 if (catal->type == XML_XML_CATALOG_TYPE) {
2635 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2636 if (ret == XML_CATAL_BREAK)
2637 ret = NULL;
2638 } else {
2639 const xmlChar *sgml;
2640
2641 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2642 if (sgml != NULL)
2643 sgml = xmlStrdup(sgml);
2644 }
2645 return(ret);
2646}
2647
2648/**
2649 * xmlACatalogDump:
2650 * @catal: a Catalog
2651 * @out: the file.
2652 *
2653 * Free up all the memory associated with catalogs
2654 */
2655void
2656xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002657 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002658 return;
2659
2660 if (catal->type == XML_XML_CATALOG_TYPE) {
2661 xmlDumpXMLCatalog(out, catal->xml);
2662 } else {
2663 xmlHashScan(catal->sgml,
2664 (xmlHashScanner) xmlCatalogDumpEntry, out);
2665 }
2666}
2667
2668/**
2669 * xmlACatalogAdd:
2670 * @catal: a Catalog
2671 * @type: the type of record to add to the catalog
2672 * @orig: the system, public or prefix to match
2673 * @replace: the replacement value for the match
2674 *
2675 * Add an entry in the catalog, it may overwrite existing but
2676 * different entries.
2677 *
2678 * Returns 0 if successful, -1 otherwise
2679 */
2680int
2681xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2682 const xmlChar * orig, const xmlChar * replace)
2683{
2684 int res = -1;
2685
2686 if (catal == NULL)
2687 return(-1);
2688
2689 if (catal->type == XML_XML_CATALOG_TYPE) {
2690 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2691 } else {
2692 xmlCatalogEntryType cattype;
2693
2694 cattype = xmlGetSGMLCatalogEntryType(type);
2695 if (cattype != XML_CATA_NONE) {
2696 xmlCatalogEntryPtr entry;
2697
Daniel Veillardc853b322001-11-06 15:24:37 +00002698 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
Daniel Veillard75b96822001-10-11 18:59:45 +00002699 XML_CATA_PREFER_NONE);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002700 if (catal->sgml == NULL)
2701 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002702 res = xmlHashAddEntry(catal->sgml, orig, entry);
2703 }
2704 }
2705 return (res);
2706}
2707
2708/**
2709 * xmlACatalogRemove:
2710 * @catal: a Catalog
2711 * @value: the value to remove
2712 *
2713 * Remove an entry from the catalog
2714 *
2715 * Returns the number of entries removed if successful, -1 otherwise
2716 */
2717int
2718xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2719 int res = -1;
2720
2721 if ((catal == NULL) || (value == NULL))
2722 return(-1);
2723
2724 if (catal->type == XML_XML_CATALOG_TYPE) {
2725 res = xmlDelXMLCatalog(catal->xml, value);
2726 } else {
2727 res = xmlHashRemoveEntry(catal->sgml, value,
2728 (xmlHashDeallocator) xmlFreeCatalogEntry);
2729 if (res == 0)
2730 res = 1;
2731 }
2732 return(res);
2733}
2734
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002735/**
2736 * xmlNewCatalog:
2737 * @sgml: should this create an SGML catalog
2738 *
2739 * create a new Catalog.
2740 *
2741 * Returns the xmlCatalogPtr or NULL in case of error
2742 */
2743xmlCatalogPtr
2744xmlNewCatalog(int sgml) {
2745 xmlCatalogPtr catal = NULL;
2746
2747 if (sgml) {
2748 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
2749 xmlCatalogDefaultPrefer);
2750 if ((catal != NULL) && (catal->sgml == NULL))
2751 catal->sgml = xmlHashCreate(10);
2752 } else
2753 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
2754 xmlCatalogDefaultPrefer);
2755 return(catal);
2756}
2757
2758/**
2759 * xmlCatalogIsEmpty:
2760 * @catal: should this create an SGML catalog
2761 *
2762 * Check is a catalog is empty
2763 *
2764 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
2765 */
2766int
2767xmlCatalogIsEmpty(xmlCatalogPtr catal) {
2768 if (catal == NULL)
2769 return(-1);
2770
2771 if (catal->type == XML_XML_CATALOG_TYPE) {
2772 if (catal->xml == NULL)
2773 return(1);
2774 if ((catal->xml->type != XML_CATA_CATALOG) &&
2775 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
2776 return(-1);
2777 if (catal->xml->children == NULL)
2778 return(1);
2779 return(0);
2780 } else {
2781 int res;
2782
2783 if (catal->sgml == NULL)
2784 return(1);
2785 res = xmlHashSize(catal->sgml);
2786 if (res == 0)
2787 return(1);
2788 if (res < 0)
2789 return(-1);
2790 }
2791 return(0);
2792}
2793
Daniel Veillard75b96822001-10-11 18:59:45 +00002794/************************************************************************
2795 * *
2796 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002797 * *
2798 ************************************************************************/
2799
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002800/**
Daniel Veillard81463942001-10-16 12:34:39 +00002801 * xmlInitializeCatalogData:
2802 *
2803 * Do the catalog initialization only of global data, doesn't try to load
2804 * any catalog actually.
2805 * this function is not thread safe, catalog initialization should
2806 * preferably be done once at startup
2807 */
2808static void
2809xmlInitializeCatalogData(void) {
2810 if (xmlCatalogInitialized != 0)
2811 return;
2812
2813 if (getenv("XML_DEBUG_CATALOG"))
2814 xmlDebugCatalogs = 1;
2815 xmlCatalogMutex = xmlNewRMutex();
2816
2817 xmlCatalogInitialized = 1;
2818}
2819/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002820 * xmlInitializeCatalog:
2821 *
2822 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002823 * this function is not thread safe, catalog initialization should
2824 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002825 */
2826void
2827xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002828 if (xmlCatalogInitialized != 0)
2829 return;
2830
Daniel Veillard81463942001-10-16 12:34:39 +00002831 xmlInitializeCatalogData();
2832 xmlRMutexLock(xmlCatalogMutex);
2833
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002834 if (getenv("XML_DEBUG_CATALOG"))
2835 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002836
Daniel Veillard75b96822001-10-11 18:59:45 +00002837 if (xmlDefaultCatalog == NULL) {
2838 const char *catalogs;
2839 xmlCatalogPtr catal;
2840
Daniel Veillardb44025c2001-10-11 22:55:55 +00002841 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002842 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002843 catalogs = XML_XML_DEFAULT_CATALOG;
2844
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002845 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002846 if (catal != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002847
Daniel Veillardc853b322001-11-06 15:24:37 +00002848 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002849 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002850
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002851 xmlDefaultCatalog = catal;
2852 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002853 }
2854
Daniel Veillard81463942001-10-16 12:34:39 +00002855 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002856}
2857
Daniel Veillard82d75332001-10-08 15:01:59 +00002858
2859/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002860 * xmlLoadCatalog:
2861 * @filename: a file path
2862 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002863 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002864 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002865 * this function is not thread safe, catalog initialization should
2866 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002867 *
2868 * Returns 0 in case of success -1 in case of error
2869 */
2870int
Daniel Veillard16756b62001-10-01 07:36:25 +00002871xmlLoadCatalog(const char *filename)
2872{
Daniel Veillard75b96822001-10-11 18:59:45 +00002873 int ret;
2874 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002875
Daniel Veillard81463942001-10-16 12:34:39 +00002876 if (!xmlCatalogInitialized)
2877 xmlInitializeCatalogData();
2878
2879 xmlRMutexLock(xmlCatalogMutex);
2880
Daniel Veillard75b96822001-10-11 18:59:45 +00002881 if (xmlDefaultCatalog == NULL) {
2882 catal = xmlLoadACatalog(filename);
2883 if (catal == NULL)
2884 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002885
Daniel Veillard75b96822001-10-11 18:59:45 +00002886 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002887 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002888 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002889 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002890
Daniel Veillard75b96822001-10-11 18:59:45 +00002891 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002892 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002893 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002894}
2895
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002896/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002897 * xmlLoadCatalogs:
2898 * @paths: a list of file path separated by ':' or spaces
2899 *
2900 * Load the catalogs and makes their definitions effective for the default
2901 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002902 * this function is not thread safe, catalog initialization should
2903 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002904 */
2905void
2906xmlLoadCatalogs(const char *pathss) {
2907 const char *cur;
2908 const char *paths;
2909 xmlChar *path;
2910
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002911 if (pathss == NULL)
2912 return;
2913
Daniel Veillard81418e32001-05-22 15:08:55 +00002914 cur = pathss;
2915 while ((cur != NULL) && (*cur != 0)) {
2916 while (IS_BLANK(*cur)) cur++;
2917 if (*cur != 0) {
2918 paths = cur;
2919 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2920 cur++;
2921 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2922 if (path != NULL) {
2923 xmlLoadCatalog((const char *) path);
2924 xmlFree(path);
2925 }
2926 }
2927 while (*cur == ':')
2928 cur++;
2929 }
2930}
2931
Daniel Veillarda7374592001-05-10 14:17:55 +00002932/**
2933 * xmlCatalogCleanup:
2934 *
2935 * Free up all the memory associated with catalogs
2936 */
2937void
2938xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00002939 if (xmlCatalogInitialized == 0)
2940 return;
2941
Daniel Veillard81463942001-10-16 12:34:39 +00002942 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002943 if (xmlDebugCatalogs)
2944 xmlGenericError(xmlGenericErrorContext,
2945 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002946 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002947 xmlHashFree(xmlCatalogXMLFiles,
2948 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002949 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002950 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002951 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002952 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002953 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002954 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00002955 xmlRMutexUnlock(xmlCatalogMutex);
2956 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00002957}
2958
2959/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002960 * xmlCatalogResolveSystem:
2961 * @sysId: the public ID string
2962 *
2963 * Try to lookup the catalog resource for a system ID
2964 *
2965 * Returns the system ID if found or NULL otherwise, the value returned
2966 * must be freed by the caller.
2967 */
2968xmlChar *
2969xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002970 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002971
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002972 if (!xmlCatalogInitialized)
2973 xmlInitializeCatalog();
2974
Daniel Veillard75b96822001-10-11 18:59:45 +00002975 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
2976 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002977}
2978
2979/**
2980 * xmlCatalogResolvePublic:
2981 * @pubId: the public ID string
2982 *
2983 * Try to lookup the system ID associated to a public ID
2984 *
2985 * Returns the system ID if found or NULL otherwise, the value returned
2986 * must be freed by the caller.
2987 */
2988xmlChar *
2989xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002990 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002991
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002992 if (!xmlCatalogInitialized)
2993 xmlInitializeCatalog();
2994
Daniel Veillard75b96822001-10-11 18:59:45 +00002995 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
2996 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002997}
Daniel Veillard344cee72001-08-20 00:08:40 +00002998
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002999/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003000 * xmlCatalogResolve:
3001 * @pubId: the public ID string
3002 * @sysId: the system ID string
3003 *
3004 * Do a complete resolution lookup of an External Identifier
3005 *
3006 * Returns the URI of the resource or NULL if not found, it must be freed
3007 * by the caller.
3008 */
3009xmlChar *
3010xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003011 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003012
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003013 if (!xmlCatalogInitialized)
3014 xmlInitializeCatalog();
3015
Daniel Veillard75b96822001-10-11 18:59:45 +00003016 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3017 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003018}
3019
3020/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003021 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003022 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003023 *
3024 * Do a complete resolution lookup of an URI
3025 *
3026 * Returns the URI of the resource or NULL if not found, it must be freed
3027 * by the caller.
3028 */
3029xmlChar *
3030xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003031 xmlChar *ret;
3032
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003033 if (!xmlCatalogInitialized)
3034 xmlInitializeCatalog();
3035
Daniel Veillard75b96822001-10-11 18:59:45 +00003036 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3037 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003038}
3039
3040/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003041 * xmlCatalogDump:
3042 * @out: the file.
3043 *
3044 * Free up all the memory associated with catalogs
3045 */
3046void
3047xmlCatalogDump(FILE *out) {
3048 if (out == NULL)
3049 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003050
Daniel Veillard75b96822001-10-11 18:59:45 +00003051 if (!xmlCatalogInitialized)
3052 xmlInitializeCatalog();
3053
3054 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003055}
3056
3057/**
3058 * xmlCatalogAdd:
3059 * @type: the type of record to add to the catalog
3060 * @orig: the system, public or prefix to match
3061 * @replace: the replacement value for the match
3062 *
3063 * Add an entry in the catalog, it may overwrite existing but
3064 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003065 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003066 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003067 *
3068 * Returns 0 if successful, -1 otherwise
3069 */
3070int
3071xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3072 int res = -1;
3073
Daniel Veillard81463942001-10-16 12:34:39 +00003074 if (!xmlCatalogInitialized)
3075 xmlInitializeCatalogData();
3076
3077 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003078 /*
3079 * Specific case where one want to override the default catalog
3080 * put in place by xmlInitializeCatalog();
3081 */
3082 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003083 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003084 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003085 xmlCatalogDefaultPrefer);
3086 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
Daniel Veillardc853b322001-11-06 15:24:37 +00003087 orig, NULL, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00003088
Daniel Veillard81463942001-10-16 12:34:39 +00003089 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003090 return(0);
3091 }
3092
Daniel Veillard75b96822001-10-11 18:59:45 +00003093 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003094 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003095 return(res);
3096}
3097
3098/**
3099 * xmlCatalogRemove:
3100 * @value: the value to remove
3101 *
3102 * Remove an entry from the catalog
3103 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003104 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003105 */
3106int
3107xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003108 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003109
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003110 if (!xmlCatalogInitialized)
3111 xmlInitializeCatalog();
3112
Daniel Veillard81463942001-10-16 12:34:39 +00003113 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003114 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003115 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003116 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003117}
3118
3119/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003120 * xmlCatalogConvert:
3121 *
3122 * Convert all the SGML catalog entries as XML ones
3123 *
3124 * Returns the number of entries converted if successful, -1 otherwise
3125 */
3126int
3127xmlCatalogConvert(void) {
3128 int res = -1;
3129
3130 if (!xmlCatalogInitialized)
3131 xmlInitializeCatalog();
3132
Daniel Veillard81463942001-10-16 12:34:39 +00003133 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003134 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003135 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003136 return(res);
3137}
3138
Daniel Veillard75b96822001-10-11 18:59:45 +00003139/************************************************************************
3140 * *
3141 * Public interface manipulating the common preferences *
3142 * *
3143 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003144
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003145/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003146 * xmlCatalogGetDefaults:
3147 *
3148 * Used to get the user preference w.r.t. to what catalogs should
3149 * be accepted
3150 *
3151 * Returns the current xmlCatalogAllow value
3152 */
3153xmlCatalogAllow
3154xmlCatalogGetDefaults(void) {
3155 return(xmlCatalogDefaultAllow);
3156}
3157
3158/**
3159 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003160 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003161 *
3162 * Used to set the user preference w.r.t. to what catalogs should
3163 * be accepted
3164 */
3165void
3166xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003167 if (xmlDebugCatalogs) {
3168 switch (allow) {
3169 case XML_CATA_ALLOW_NONE:
3170 xmlGenericError(xmlGenericErrorContext,
3171 "Disabling catalog usage\n");
3172 break;
3173 case XML_CATA_ALLOW_GLOBAL:
3174 xmlGenericError(xmlGenericErrorContext,
3175 "Allowing only global catalogs\n");
3176 break;
3177 case XML_CATA_ALLOW_DOCUMENT:
3178 xmlGenericError(xmlGenericErrorContext,
3179 "Allowing only catalogs from the document\n");
3180 break;
3181 case XML_CATA_ALLOW_ALL:
3182 xmlGenericError(xmlGenericErrorContext,
3183 "Allowing all catalogs\n");
3184 break;
3185 }
3186 }
3187 xmlCatalogDefaultAllow = allow;
3188}
3189
3190/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003191 * xmlCatalogSetDefaultPrefer:
3192 * @prefer: the default preference for delegation
3193 *
3194 * Allows to set the preference between public and system for deletion
3195 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003196 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003197 *
3198 * Returns the previous value of the default preference for delegation
3199 */
3200xmlCatalogPrefer
3201xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3202 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3203
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003204 if (prefer == XML_CATA_PREFER_NONE)
3205 return(ret);
3206
3207 if (xmlDebugCatalogs) {
3208 switch (prefer) {
3209 case XML_CATA_PREFER_PUBLIC:
3210 xmlGenericError(xmlGenericErrorContext,
3211 "Setting catalog preference to PUBLIC\n");
3212 break;
3213 case XML_CATA_PREFER_SYSTEM:
3214 xmlGenericError(xmlGenericErrorContext,
3215 "Setting catalog preference to SYSTEM\n");
3216 break;
3217 case XML_CATA_PREFER_NONE:
3218 break;
3219 }
3220 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003221 xmlCatalogDefaultPrefer = prefer;
3222 return(ret);
3223}
3224
3225/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003226 * xmlCatalogSetDebug:
3227 * @level: the debug level of catalogs required
3228 *
3229 * Used to set the debug level for catalog operation, 0 disable
3230 * debugging, 1 enable it
3231 *
3232 * Returns the previous value of the catalog debugging level
3233 */
3234int
3235xmlCatalogSetDebug(int level) {
3236 int ret = xmlDebugCatalogs;
3237
3238 if (level <= 0)
3239 xmlDebugCatalogs = 0;
3240 else
3241 xmlDebugCatalogs = level;
3242 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003243}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003244
Daniel Veillard75b96822001-10-11 18:59:45 +00003245/************************************************************************
3246 * *
3247 * Minimal interfaces used for per-document catalogs by the parser *
3248 * *
3249 ************************************************************************/
3250
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003251/**
3252 * xmlCatalogFreeLocal:
3253 * @catalogs: a document's list of catalogs
3254 *
3255 * Free up the memory associated to the catalog list
3256 */
3257void
3258xmlCatalogFreeLocal(void *catalogs) {
3259 xmlCatalogEntryPtr catal;
3260
Daniel Veillard81463942001-10-16 12:34:39 +00003261 if (!xmlCatalogInitialized)
3262 xmlInitializeCatalog();
3263
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003264 catal = (xmlCatalogEntryPtr) catalogs;
3265 if (catal != NULL)
3266 xmlFreeCatalogEntryList(catal);
3267}
3268
3269
3270/**
3271 * xmlCatalogAddLocal:
3272 * @catalogs: a document's list of catalogs
3273 * @URL: the URL to a new local catalog
3274 *
3275 * Add the new entry to the catalog list
3276 *
3277 * Returns the updated list
3278 */
3279void *
3280xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3281 xmlCatalogEntryPtr catal, add;
3282
3283 if (!xmlCatalogInitialized)
3284 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003285
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003286 if (URL == NULL)
3287 return(catalogs);
3288
3289 if (xmlDebugCatalogs)
3290 xmlGenericError(xmlGenericErrorContext,
3291 "Adding document catalog %s\n", URL);
3292
Daniel Veillardc853b322001-11-06 15:24:37 +00003293 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003294 xmlCatalogDefaultPrefer);
3295 if (add == NULL)
3296 return(catalogs);
3297
3298 catal = (xmlCatalogEntryPtr) catalogs;
3299 if (catal == NULL)
3300 return((void *) add);
3301
3302 while (catal->next != NULL)
3303 catal = catal->next;
3304 catal->next = add;
3305 return(catalogs);
3306}
3307
3308/**
3309 * xmlCatalogLocalResolve:
3310 * @catalogs: a document's list of catalogs
3311 * @pubId: the public ID string
3312 * @sysId: the system ID string
3313 *
3314 * Do a complete resolution lookup of an External Identifier using a
3315 * document's private catalog list
3316 *
3317 * Returns the URI of the resource or NULL if not found, it must be freed
3318 * by the caller.
3319 */
3320xmlChar *
3321xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3322 const xmlChar *sysID) {
3323 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003324 xmlChar *ret;
3325
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003326 if (!xmlCatalogInitialized)
3327 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003328
Daniel Veillard81463942001-10-16 12:34:39 +00003329 if ((pubID == NULL) && (sysID == NULL))
3330 return(NULL);
3331
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003332 if (xmlDebugCatalogs) {
3333 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003334 xmlGenericError(xmlGenericErrorContext,
3335 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003336 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003337 xmlGenericError(xmlGenericErrorContext,
3338 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003339 }
3340 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003341
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003342 catal = (xmlCatalogEntryPtr) catalogs;
3343 if (catal == NULL)
3344 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003345 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3346 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3347 return(ret);
3348 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003349}
3350
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003351/**
3352 * xmlCatalogLocalResolveURI:
3353 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003354 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003355 *
3356 * Do a complete resolution lookup of an URI using a
3357 * document's private catalog list
3358 *
3359 * Returns the URI of the resource or NULL if not found, it must be freed
3360 * by the caller.
3361 */
3362xmlChar *
3363xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3364 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003365 xmlChar *ret;
3366
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003367 if (!xmlCatalogInitialized)
3368 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003369
Daniel Veillard81463942001-10-16 12:34:39 +00003370 if (URI == NULL)
3371 return(NULL);
3372
Daniel Veillard6990bf32001-08-23 21:17:48 +00003373 if (xmlDebugCatalogs)
3374 xmlGenericError(xmlGenericErrorContext,
3375 "Resolve URI %s\n", URI);
3376
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003377 catal = (xmlCatalogEntryPtr) catalogs;
3378 if (catal == NULL)
3379 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003380 ret = xmlCatalogListXMLResolveURI(catal, URI);
3381 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3382 return(ret);
3383 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003384}
3385
Daniel Veillard75b96822001-10-11 18:59:45 +00003386/************************************************************************
3387 * *
3388 * Deprecated interfaces *
3389 * *
3390 ************************************************************************/
3391/**
3392 * xmlCatalogGetSystem:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003393 * @sysId: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003394 *
3395 * Try to lookup the system ID associated to a public ID
3396 * DEPRECATED, use xmlCatalogResolveSystem()
3397 *
3398 * Returns the system ID if found or NULL otherwise.
3399 */
3400const xmlChar *
3401xmlCatalogGetSystem(const xmlChar *sysID) {
3402 xmlChar *ret;
3403 static xmlChar result[1000];
3404 static int msg = 0;
3405
Daniel Veillard81463942001-10-16 12:34:39 +00003406 if (!xmlCatalogInitialized)
3407 xmlInitializeCatalog();
3408
Daniel Veillard75b96822001-10-11 18:59:45 +00003409 if (msg == 0) {
3410 xmlGenericError(xmlGenericErrorContext,
3411 "Use of deprecated xmlCatalogGetSystem() call\n");
3412 msg++;
3413 }
3414
3415 if (sysID == NULL)
3416 return(NULL);
3417
Daniel Veillard75b96822001-10-11 18:59:45 +00003418 /*
3419 * Check first the XML catalogs
3420 */
3421 if (xmlDefaultCatalog != NULL) {
3422 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3423 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3424 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3425 result[sizeof(result) - 1] = 0;
3426 return(result);
3427 }
3428 }
3429
3430 if (xmlDefaultCatalog != NULL)
3431 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3432 return(NULL);
3433}
3434
3435/**
3436 * xmlCatalogGetPublic:
3437 * @pubId: the public ID string
3438 *
3439 * Try to lookup the system ID associated to a public ID
3440 * DEPRECATED, use xmlCatalogResolvePublic()
3441 *
3442 * Returns the system ID if found or NULL otherwise.
3443 */
3444const xmlChar *
3445xmlCatalogGetPublic(const xmlChar *pubID) {
3446 xmlChar *ret;
3447 static xmlChar result[1000];
3448 static int msg = 0;
3449
Daniel Veillard81463942001-10-16 12:34:39 +00003450 if (!xmlCatalogInitialized)
3451 xmlInitializeCatalog();
3452
Daniel Veillard75b96822001-10-11 18:59:45 +00003453 if (msg == 0) {
3454 xmlGenericError(xmlGenericErrorContext,
3455 "Use of deprecated xmlCatalogGetPublic() call\n");
3456 msg++;
3457 }
3458
3459 if (pubID == NULL)
3460 return(NULL);
3461
Daniel Veillard75b96822001-10-11 18:59:45 +00003462 /*
3463 * Check first the XML catalogs
3464 */
3465 if (xmlDefaultCatalog != NULL) {
3466 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3467 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3468 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3469 result[sizeof(result) - 1] = 0;
3470 return(result);
3471 }
3472 }
3473
3474 if (xmlDefaultCatalog != NULL)
3475 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3476 return(NULL);
3477}
3478
Daniel Veillarda7374592001-05-10 14:17:55 +00003479#endif /* LIBXML_CATALOG_ENABLED */