blob: 287d4aa702fcbad2fa23676d137d49be1e284288 [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 Veillarda7374592001-05-10 14:17:55 +000041
Daniel Veillard6990bf32001-08-23 21:17:48 +000042#define MAX_DELEGATE 50
43
Daniel Veillard344cee72001-08-20 00:08:40 +000044/**
45 * TODO:
46 *
47 * macro to flag unimplemented blocks
48 */
49#define TODO \
50 xmlGenericError(xmlGenericErrorContext, \
51 "Unimplemented block at %s:%d\n", \
52 __FILE__, __LINE__);
53
Daniel Veillardcda96922001-08-21 10:56:31 +000054#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000055#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000056#ifndef XML_XML_DEFAULT_CATALOG
57#define XML_XML_DEFAULT_CATALOG "/etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000058#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000059#ifndef XML_SGML_DEFAULT_CATALOG
60#define XML_SGML_DEFAULT_CATALOG "/etc/sgml/catalog"
61#endif
62
Daniel Veillard85c11fa2001-10-16 21:03:08 +000063static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000064
Daniel Veillarda7374592001-05-10 14:17:55 +000065/************************************************************************
66 * *
67 * Types, all private *
68 * *
69 ************************************************************************/
70
71typedef enum {
72 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000073 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000074 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000075 XML_CATA_NEXT_CATALOG,
76 XML_CATA_PUBLIC,
77 XML_CATA_SYSTEM,
78 XML_CATA_REWRITE_SYSTEM,
79 XML_CATA_DELEGATE_PUBLIC,
80 XML_CATA_DELEGATE_SYSTEM,
81 XML_CATA_URI,
82 XML_CATA_REWRITE_URI,
83 XML_CATA_DELEGATE_URI,
84 SGML_CATA_SYSTEM,
85 SGML_CATA_PUBLIC,
86 SGML_CATA_ENTITY,
87 SGML_CATA_PENTITY,
88 SGML_CATA_DOCTYPE,
89 SGML_CATA_LINKTYPE,
90 SGML_CATA_NOTATION,
91 SGML_CATA_DELEGATE,
92 SGML_CATA_BASE,
93 SGML_CATA_CATALOG,
94 SGML_CATA_DOCUMENT,
95 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000096} xmlCatalogEntryType;
97
98typedef struct _xmlCatalogEntry xmlCatalogEntry;
99typedef xmlCatalogEntry *xmlCatalogEntryPtr;
100struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000101 struct _xmlCatalogEntry *next;
102 struct _xmlCatalogEntry *parent;
103 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000104 xmlCatalogEntryType type;
105 xmlChar *name;
106 xmlChar *value;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000107 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000108 int dealloc;
Daniel Veillarda7374592001-05-10 14:17:55 +0000109};
110
Daniel Veillard75b96822001-10-11 18:59:45 +0000111typedef enum {
112 XML_XML_CATALOG_TYPE = 1,
113 XML_SGML_CATALOG_TYPE
114} xmlCatalogType;
115
116#define XML_MAX_SGML_CATA_DEPTH 10
117struct _xmlCatalog {
118 xmlCatalogType type; /* either XML or SGML */
119
120 /*
121 * SGML Catalogs are stored as a simple hash table of catalog entries
122 * Catalog stack to check against overflows when building the
123 * SGML catalog
124 */
125 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
126 int catalNr; /* Number of current catal streams */
127 int catalMax; /* Max number of catal streams */
128 xmlHashTablePtr sgml;
129
130 /*
131 * XML Catalogs are stored as a tree of Catalog entries
132 */
133 xmlCatalogPrefer prefer;
134 xmlCatalogEntryPtr xml;
135};
136
137/************************************************************************
138 * *
139 * Global variables *
140 * *
141 ************************************************************************/
142
Daniel Veillard81463942001-10-16 12:34:39 +0000143/*
144 * Those are preferences
145 */
146static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000147static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000148static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000149
150/*
151 * Hash table containing all the trees of XML catalogs parsed by
152 * the application.
153 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000154static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000155
156/*
157 * The default catalog in use by the application
158 */
159static xmlCatalogPtr xmlDefaultCatalog = NULL;
160
161/*
Daniel Veillard81463942001-10-16 12:34:39 +0000162 * A mutex for modifying the shared global catalog(s)
163 * xmlDefaultCatalog tree.
164 * It also protects xmlCatalogXMLFiles
165 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
166 */
167static xmlRMutexPtr xmlCatalogMutex = NULL;
168
169/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000170 * Whether the catalog support was initialized.
171 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000172static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000173
Daniel Veillarda7374592001-05-10 14:17:55 +0000174
175/************************************************************************
176 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000177 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000178 * *
179 ************************************************************************/
180
Daniel Veillard75b96822001-10-11 18:59:45 +0000181/**
182 * xmlNewCatalogEntry:
183 * @type: type of entry
184 * @name: name of the entry
185 * @value: value of the entry
186 * @prefer: the PUBLIC vs. SYSTEM current preference value
187 *
188 * create a new Catalog entry, this type is shared both by XML and
189 * SGML catalogs, but the acceptable types values differs.
190 *
191 * Returns the xmlCatalogEntryPtr or NULL in case of error
192 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000193static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000194xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000195 const xmlChar *value, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000196 xmlCatalogEntryPtr ret;
197
198 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
199 if (ret == NULL) {
200 xmlGenericError(xmlGenericErrorContext,
201 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
202 return(NULL);
203 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000204 ret->next = NULL;
205 ret->parent = NULL;
206 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000207 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000208 if (name != NULL)
209 ret->name = xmlStrdup(name);
210 else
211 ret->name = NULL;
212 if (value != NULL)
213 ret->value = xmlStrdup(value);
214 else
215 ret->value = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000216 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000217 ret->dealloc = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +0000218 return(ret);
219}
220
221static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000222xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
223
Daniel Veillard75b96822001-10-11 18:59:45 +0000224/**
225 * xmlFreeCatalogEntry:
226 * @ret: a Catalog entry
227 *
228 * Free the memory allocated to a Catalog entry
229 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000230static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000231xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
232 if (ret == NULL)
233 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000234 /*
235 * Entries stored in the file hash must be dealloacted
236 * only by the file hash cleaner !
237 */
238 if (ret->dealloc == 1)
239 return;
240
241 if (xmlDebugCatalogs) {
242 if (ret->name != NULL)
243 xmlGenericError(xmlGenericErrorContext,
244 "Free catalog entry %s\n", ret->name);
245 else if (ret->value != NULL)
246 xmlGenericError(xmlGenericErrorContext,
247 "Free catalog entry %s\n", ret->value);
248 else
249 xmlGenericError(xmlGenericErrorContext,
250 "Free catalog entry\n");
251 }
252
Daniel Veillarda7374592001-05-10 14:17:55 +0000253 if (ret->name != NULL)
254 xmlFree(ret->name);
255 if (ret->value != NULL)
256 xmlFree(ret->value);
257 xmlFree(ret);
258}
259
Daniel Veillard75b96822001-10-11 18:59:45 +0000260/**
261 * xmlFreeCatalogEntryList:
262 * @ret: a Catalog entry list
263 *
264 * Free the memory allocated to a full chained list of Catalog entries
265 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000266static void
267xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
268 xmlCatalogEntryPtr next;
269
270 while (ret != NULL) {
271 next = ret->next;
272 xmlFreeCatalogEntry(ret);
273 ret = next;
274 }
275}
276
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000277/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000278 * xmlFreeCatalogHashEntryList:
279 * @ret: a Catalog entry list
280 *
281 * Free the memory allocated to list of Catalog entries from the
282 * catalog file hash.
283 */
284static void
285xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
286 xmlCatalogEntryPtr children, next;
287
288 if (catal == NULL)
289 return;
290
291 children = catal->children;
292 while (children != NULL) {
293 next = children->next;
294 children->dealloc = 0;
295 children->children = NULL;
296 xmlFreeCatalogEntry(children);
297 children = next;
298 }
299 catal->dealloc = 0;
300 xmlFreeCatalogEntry(catal);
301}
302
303/**
Daniel Veillard75b96822001-10-11 18:59:45 +0000304 * xmlNewCatalog:
305 * @type: type of catalog
306 * @prefer: the PUBLIC vs. SYSTEM current preference value
307 *
308 * create a new Catalog, this type is shared both by XML and
309 * SGML catalogs, but the acceptable types values differs.
310 *
311 * Returns the xmlCatalogPtr or NULL in case of error
312 */
313static xmlCatalogPtr
314xmlNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
315 xmlCatalogPtr ret;
316
317 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
318 if (ret == NULL) {
319 xmlGenericError(xmlGenericErrorContext,
320 "malloc of %d byte failed\n", sizeof(xmlCatalog));
321 return(NULL);
322 }
323 memset(ret, 0, sizeof(xmlCatalog));
324 ret->type = type;
325 ret->catalNr = 0;
326 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
327 ret->prefer = prefer;
328 return(ret);
329}
330
331/**
332 * xmlFreeCatalog:
333 * @catal: a Catalog entry
334 *
335 * Free the memory allocated to a Catalog
336 */
337void
338xmlFreeCatalog(xmlCatalogPtr catal) {
339 if (catal == NULL)
340 return;
341 if (catal->xml != NULL)
342 xmlFreeCatalogEntryList(catal->xml);
343 if (catal->sgml != NULL)
344 xmlHashFree(catal->sgml,
345 (xmlHashDeallocator) xmlFreeCatalogEntry);
346 xmlFree(catal);
347}
348
349/************************************************************************
350 * *
351 * Serializing Catalogs *
352 * *
353 ************************************************************************/
354
355/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000356 * xmlCatalogDumpEntry:
357 * @entry: the
358 * @out: the file.
359 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000360 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000361 */
362static void
363xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
364 if ((entry == NULL) || (out == NULL))
365 return;
366 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000367 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000368 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000369 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000370 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000371 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000372 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000373 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000374 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000375 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000376 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000377 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000378 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000379 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000380 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000381 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000382 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000383 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000384 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000385 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000386 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000387 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000388 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000389 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000390 fprintf(out, "SGMLDECL "); break;
391 default:
392 return;
393 }
394 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000395 case SGML_CATA_ENTITY:
396 case SGML_CATA_PENTITY:
397 case SGML_CATA_DOCTYPE:
398 case SGML_CATA_LINKTYPE:
399 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000400 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000401 case SGML_CATA_PUBLIC:
402 case SGML_CATA_SYSTEM:
403 case SGML_CATA_SGMLDECL:
404 case SGML_CATA_DOCUMENT:
405 case SGML_CATA_CATALOG:
406 case SGML_CATA_BASE:
407 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000408 fprintf(out, "\"%s\"", entry->name); break;
409 default:
410 break;
411 }
412 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000413 case SGML_CATA_ENTITY:
414 case SGML_CATA_PENTITY:
415 case SGML_CATA_DOCTYPE:
416 case SGML_CATA_LINKTYPE:
417 case SGML_CATA_NOTATION:
418 case SGML_CATA_PUBLIC:
419 case SGML_CATA_SYSTEM:
420 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000421 fprintf(out, " \"%s\"", entry->value); break;
422 default:
423 break;
424 }
425 fprintf(out, "\n");
426}
427
Daniel Veillard75b96822001-10-11 18:59:45 +0000428static int
429xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
430 int ret;
431 xmlDocPtr doc;
432 xmlNsPtr ns;
433 xmlDtdPtr dtd;
434 xmlNodePtr node, catalog;
435 xmlOutputBufferPtr buf;
436 xmlCatalogEntryPtr cur;
437
438 /*
439 * Rebuild a catalog
440 */
441 doc = xmlNewDoc(NULL);
442 if (doc == NULL)
443 return(-1);
444 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
445 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
446BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
447
448 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
449
450 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
451 if (ns == NULL) {
452 xmlFreeDoc(doc);
453 return(-1);
454 }
455 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
456 if (catalog == NULL) {
457 xmlFreeNs(ns);
458 xmlFreeDoc(doc);
459 return(-1);
460 }
461 catalog->nsDef = ns;
462 xmlAddChild((xmlNodePtr) doc, catalog);
463
464 /*
465 * add all the catalog entries
466 */
467 cur = catal;
468 while (cur != NULL) {
469 switch (cur->type) {
470 case XML_CATA_BROKEN_CATALOG:
471 case XML_CATA_CATALOG:
472 if (cur == catal) {
473 cur = cur->children;
474 continue;
475 }
476 break;
477 case XML_CATA_NEXT_CATALOG:
478 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
479 xmlSetProp(node, BAD_CAST "catalog", cur->value);
480 xmlAddChild(catalog, node);
481 break;
482 case XML_CATA_NONE:
483 break;
484 case XML_CATA_PUBLIC:
485 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
486 xmlSetProp(node, BAD_CAST "publicId", cur->name);
487 xmlSetProp(node, BAD_CAST "uri", cur->value);
488 xmlAddChild(catalog, node);
489 break;
490 case XML_CATA_SYSTEM:
491 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
492 xmlSetProp(node, BAD_CAST "systemId", cur->name);
493 xmlSetProp(node, BAD_CAST "uri", cur->value);
494 xmlAddChild(catalog, node);
495 break;
496 case XML_CATA_REWRITE_SYSTEM:
497 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
498 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
499 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
500 xmlAddChild(catalog, node);
501 break;
502 case XML_CATA_DELEGATE_PUBLIC:
503 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
504 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
505 xmlSetProp(node, BAD_CAST "catalog", cur->value);
506 xmlAddChild(catalog, node);
507 break;
508 case XML_CATA_DELEGATE_SYSTEM:
509 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
510 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
511 xmlSetProp(node, BAD_CAST "catalog", cur->value);
512 xmlAddChild(catalog, node);
513 break;
514 case XML_CATA_URI:
515 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
516 xmlSetProp(node, BAD_CAST "name", cur->name);
517 xmlSetProp(node, BAD_CAST "uri", cur->value);
518 xmlAddChild(catalog, node);
519 break;
520 case XML_CATA_REWRITE_URI:
521 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
522 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
523 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
524 xmlAddChild(catalog, node);
525 break;
526 case XML_CATA_DELEGATE_URI:
527 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
528 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
529 xmlSetProp(node, BAD_CAST "catalog", cur->value);
530 xmlAddChild(catalog, node);
531 break;
532 case SGML_CATA_SYSTEM:
533 case SGML_CATA_PUBLIC:
534 case SGML_CATA_ENTITY:
535 case SGML_CATA_PENTITY:
536 case SGML_CATA_DOCTYPE:
537 case SGML_CATA_LINKTYPE:
538 case SGML_CATA_NOTATION:
539 case SGML_CATA_DELEGATE:
540 case SGML_CATA_BASE:
541 case SGML_CATA_CATALOG:
542 case SGML_CATA_DOCUMENT:
543 case SGML_CATA_SGMLDECL:
544 break;
545 }
546 cur = cur->next;
547 }
548
549 /*
550 * reserialize it
551 */
552 buf = xmlOutputBufferCreateFile(out, NULL);
553 if (buf == NULL) {
554 xmlFreeDoc(doc);
555 return(-1);
556 }
557 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
558
559 /*
560 * Free it
561 */
562 xmlFreeDoc(doc);
563
564 return(ret);
565}
566
567/************************************************************************
568 * *
569 * Converting SGML Catalogs to XML *
570 * *
571 ************************************************************************/
572
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000573/**
574 * xmlCatalogConvertEntry:
575 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000576 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000577 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000578 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000579 */
580static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000581xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
582 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
583 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000584 return;
585 switch (entry->type) {
586 case SGML_CATA_ENTITY:
587 entry->type = XML_CATA_PUBLIC;
588 break;
589 case SGML_CATA_PENTITY:
590 entry->type = XML_CATA_PUBLIC;
591 break;
592 case SGML_CATA_DOCTYPE:
593 entry->type = XML_CATA_PUBLIC;
594 break;
595 case SGML_CATA_LINKTYPE:
596 entry->type = XML_CATA_PUBLIC;
597 break;
598 case SGML_CATA_NOTATION:
599 entry->type = XML_CATA_PUBLIC;
600 break;
601 case SGML_CATA_PUBLIC:
602 entry->type = XML_CATA_PUBLIC;
603 break;
604 case SGML_CATA_SYSTEM:
605 entry->type = XML_CATA_SYSTEM;
606 break;
607 case SGML_CATA_DELEGATE:
608 entry->type = XML_CATA_DELEGATE_PUBLIC;
609 break;
610 case SGML_CATA_CATALOG:
611 entry->type = XML_CATA_CATALOG;
612 break;
613 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000614 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000615 (xmlHashDeallocator) xmlFreeCatalogEntry);
616 return;
617 }
618 /*
619 * Conversion successful, remove from the SGML catalog
620 * and add it to the default XML one
621 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000622 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
623 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000624 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000625 if (catal->xml->children == NULL)
626 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000627 else {
628 xmlCatalogEntryPtr prev;
629
Daniel Veillard75b96822001-10-11 18:59:45 +0000630 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000631 while (prev->next != NULL)
632 prev = prev->next;
633 prev->next = entry;
634 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000635}
636
637/**
638 * xmlConvertSGMLCatalog:
639 * @catal: the catalog
640 *
641 * Convert all the SGML catalog entries as XML ones
642 *
643 * Returns the number of entries converted if successful, -1 otherwise
644 */
645int
646xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
647
648 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
649 return(-1);
650
651 if (xmlDebugCatalogs) {
652 xmlGenericError(xmlGenericErrorContext,
653 "Converting SGML catalog to XML\n");
654 }
655 xmlHashScan(catal->sgml,
656 (xmlHashScanner) xmlCatalogConvertEntry,
657 &catal);
658 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000659}
660
Daniel Veillarda7374592001-05-10 14:17:55 +0000661/************************************************************************
662 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000663 * Helper function *
664 * *
665 ************************************************************************/
666
667/**
668 * xmlCatalogUnWrapURN:
669 * @urn: an "urn:publicid:" to unwrapp
670 *
671 * Expand the URN into the equivalent Public Identifier
672 *
673 * Returns the new identifier or NULL, the string must be deallocated
674 * by the caller.
675 */
676static xmlChar *
677xmlCatalogUnWrapURN(const xmlChar *urn) {
678 xmlChar result[2000];
679 unsigned int i = 0;
680
681 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
682 return(NULL);
683 urn += sizeof(XML_URN_PUBID) - 1;
684
685 while (*urn != 0) {
686 if (i > sizeof(result) - 3)
687 break;
688 if (*urn == '+') {
689 result[i++] = ' ';
690 urn++;
691 } else if (*urn == ':') {
692 result[i++] = '/';
693 result[i++] = '/';
694 urn++;
695 } else if (*urn == ';') {
696 result[i++] = ':';
697 result[i++] = ':';
698 urn++;
699 } else if (*urn == '%') {
700 if ((urn[1] == '2') && (urn[1] == 'B'))
701 result[i++] = '+';
702 else if ((urn[1] == '3') && (urn[1] == 'A'))
703 result[i++] = ':';
704 else if ((urn[1] == '2') && (urn[1] == 'F'))
705 result[i++] = '/';
706 else if ((urn[1] == '3') && (urn[1] == 'B'))
707 result[i++] = ';';
708 else if ((urn[1] == '2') && (urn[1] == '7'))
709 result[i++] = '\'';
710 else if ((urn[1] == '3') && (urn[1] == 'F'))
711 result[i++] = '?';
712 else if ((urn[1] == '2') && (urn[1] == '3'))
713 result[i++] = '#';
714 else if ((urn[1] == '2') && (urn[1] == '5'))
715 result[i++] = '%';
716 else {
717 result[i++] = *urn;
718 urn++;
719 continue;
720 }
721 urn += 3;
722 } else {
723 result[i++] = *urn;
724 urn++;
725 }
726 }
727 result[i] = 0;
728
729 return(xmlStrdup(result));
730}
731
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000732/**
733 * xmlParseCatalogFile:
734 * @filename: the filename
735 *
736 * parse an XML file and build a tree. It's like xmlParseFile()
737 * except it bypass all catalog lookups.
738 *
739 * Returns the resulting document tree or NULL in case of error
740 */
741
742xmlDocPtr
743xmlParseCatalogFile(const char *filename) {
744 xmlDocPtr ret;
745 xmlParserCtxtPtr ctxt;
746 char *directory = NULL;
747 xmlParserInputPtr inputStream;
748 xmlParserInputBufferPtr buf;
749
750 ctxt = xmlNewParserCtxt();
751 if (ctxt == NULL) {
752 if (xmlDefaultSAXHandler.error != NULL) {
753 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
754 }
755 return(NULL);
756 }
757
758 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
759 if (buf == NULL) {
760 xmlFreeParserCtxt(ctxt);
761 return(NULL);
762 }
763
764 inputStream = xmlNewInputStream(ctxt);
765 if (inputStream == NULL) {
766 xmlFreeParserCtxt(ctxt);
767 return(NULL);
768 }
769
770 inputStream->filename = xmlMemStrdup(filename);
771 inputStream->buf = buf;
772 inputStream->base = inputStream->buf->buffer->content;
773 inputStream->cur = inputStream->buf->buffer->content;
774 inputStream->end =
775 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
776
777 inputPush(ctxt, inputStream);
778 if ((ctxt->directory == NULL) && (directory == NULL))
779 directory = xmlParserGetDirectory(filename);
780 if ((ctxt->directory == NULL) && (directory != NULL))
781 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000782 ctxt->valid = 0;
783 ctxt->validate = 0;
784 ctxt->loadsubset = 0;
785 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000786
787 xmlParseDocument(ctxt);
788
789 if (ctxt->wellFormed)
790 ret = ctxt->myDoc;
791 else {
792 ret = NULL;
793 xmlFreeDoc(ctxt->myDoc);
794 ctxt->myDoc = NULL;
795 }
796 xmlFreeParserCtxt(ctxt);
797
798 return(ret);
799}
800
Daniel Veillard75b96822001-10-11 18:59:45 +0000801/**
802 * xmlLoadFileContent:
803 * @filename: a file path
804 *
805 * Load a file content into memory.
806 *
807 * Returns a pointer to the 0 terminated string or NULL in case of error
808 */
809static xmlChar *
810xmlLoadFileContent(const char *filename)
811{
812#ifdef HAVE_STAT
813 int fd;
814#else
815 FILE *fd;
816#endif
817 int len;
818 long size;
819
820#ifdef HAVE_STAT
821 struct stat info;
822#endif
823 xmlChar *content;
824
825 if (filename == NULL)
826 return (NULL);
827
828#ifdef HAVE_STAT
829 if (stat(filename, &info) < 0)
830 return (NULL);
831#endif
832
833#ifdef HAVE_STAT
834 if ((fd = open(filename, O_RDONLY)) < 0) {
835#else
836 if ((fd = fopen(filename, "rb")) == NULL) {
837#endif
838 return (NULL);
839 }
840#ifdef HAVE_STAT
841 size = info.st_size;
842#else
843 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
844 fclose(fd);
845 return (NULL);
846 }
847#endif
848 content = xmlMalloc(size + 10);
849 if (content == NULL) {
850 xmlGenericError(xmlGenericErrorContext,
851 "malloc of %d byte failed\n", size + 10);
852 return (NULL);
853 }
854#ifdef HAVE_STAT
855 len = read(fd, content, size);
856#else
857 len = fread(content, 1, size, fd);
858#endif
859 if (len < 0) {
860 xmlFree(content);
861 return (NULL);
862 }
863#ifdef HAVE_STAT
864 close(fd);
865#else
866 fclose(fd);
867#endif
868 content[len] = 0;
869
870 return(content);
871}
872
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000873/************************************************************************
874 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000875 * The XML Catalog parser *
876 * *
877 ************************************************************************/
878
879static xmlCatalogEntryPtr
880xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000881static xmlCatalogEntryPtr
882xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
883 const char *file);
884static void
885xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
886 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000887static xmlChar *
888xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
889 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000890static xmlChar *
891xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
892
Daniel Veillard344cee72001-08-20 00:08:40 +0000893
Daniel Veillard75b96822001-10-11 18:59:45 +0000894/**
895 * xmlGetXMLCatalogEntryType:
896 * @name: the name
897 *
898 * lookup the internal type associated to an XML catalog entry name
899 *
900 * Returns the type associate with that name
901 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000902static xmlCatalogEntryType
903xmlGetXMLCatalogEntryType(const xmlChar *name) {
904 xmlCatalogEntryType type = XML_CATA_NONE;
905 if (xmlStrEqual(name, (const xmlChar *) "system"))
906 type = XML_CATA_SYSTEM;
907 else if (xmlStrEqual(name, (const xmlChar *) "public"))
908 type = XML_CATA_PUBLIC;
909 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
910 type = XML_CATA_REWRITE_SYSTEM;
911 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
912 type = XML_CATA_DELEGATE_PUBLIC;
913 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
914 type = XML_CATA_DELEGATE_SYSTEM;
915 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
916 type = XML_CATA_URI;
917 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
918 type = XML_CATA_REWRITE_URI;
919 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
920 type = XML_CATA_DELEGATE_URI;
921 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
922 type = XML_CATA_NEXT_CATALOG;
923 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
924 type = XML_CATA_CATALOG;
925 return(type);
926}
927
Daniel Veillard75b96822001-10-11 18:59:45 +0000928/**
929 * xmlParseXMLCatalogOneNode:
930 * @cur: the XML node
931 * @type: the type of Catalog entry
932 * @name: the name of the node
933 * @attrName: the attribute holding the value
934 * @uriAttrName: the attribute holding the URI-Reference
935 * @prefer: the PUBLIC vs. SYSTEM current preference value
936 *
937 * Finishes the examination of an XML tree node of a catalog and build
938 * a Catalog entry from it.
939 *
940 * Returns the new Catalog entry node or NULL in case of error.
941 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000942static xmlCatalogEntryPtr
943xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
944 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000945 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000946 int ok = 1;
947 xmlChar *uriValue;
948 xmlChar *nameValue = NULL;
949 xmlChar *base = NULL;
950 xmlChar *URL = NULL;
951 xmlCatalogEntryPtr ret = NULL;
952
953 if (attrName != NULL) {
954 nameValue = xmlGetProp(cur, attrName);
955 if (nameValue == NULL) {
956 xmlGenericError(xmlGenericErrorContext,
957 "%s entry lacks '%s'\n", name, attrName);
958 ok = 0;
959 }
960 }
961 uriValue = xmlGetProp(cur, uriAttrName);
962 if (uriValue == NULL) {
963 xmlGenericError(xmlGenericErrorContext,
964 "%s entry lacks '%s'\n", name, uriAttrName);
965 ok = 0;
966 }
967 if (!ok) {
968 if (nameValue != NULL)
969 xmlFree(nameValue);
970 if (uriValue != NULL)
971 xmlFree(uriValue);
972 return(NULL);
973 }
974
975 base = xmlNodeGetBase(cur->doc, cur);
976 URL = xmlBuildURI(uriValue, base);
977 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000978 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000979 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000980 xmlGenericError(xmlGenericErrorContext,
981 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000982 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000983 xmlGenericError(xmlGenericErrorContext,
984 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000985 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000986 ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000987 } else {
988 xmlGenericError(xmlGenericErrorContext,
989 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
990 }
991 if (nameValue != NULL)
992 xmlFree(nameValue);
993 if (uriValue != NULL)
994 xmlFree(uriValue);
995 if (base != NULL)
996 xmlFree(base);
997 if (URL != NULL)
998 xmlFree(URL);
999 return(ret);
1000}
1001
Daniel Veillard75b96822001-10-11 18:59:45 +00001002/**
1003 * xmlParseXMLCatalogNode:
1004 * @cur: the XML node
1005 * @prefer: the PUBLIC vs. SYSTEM current preference value
1006 * @parent: the parent Catalog entry
1007 *
1008 * Examines an XML tree node of a catalog and build
1009 * a Catalog entry from it adding it to its parent. The examination can
1010 * be recursive.
1011 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001012static void
1013xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1014 xmlCatalogEntryPtr parent)
1015{
1016 xmlChar *uri = NULL;
1017 xmlChar *URL = NULL;
1018 xmlChar *base = NULL;
1019 xmlCatalogEntryPtr entry = NULL;
1020
1021 if (cur == NULL)
1022 return;
1023 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1024 xmlChar *prop;
1025
1026 prop = xmlGetProp(cur, BAD_CAST "prefer");
1027 if (prop != NULL) {
1028 if (xmlStrEqual(prop, BAD_CAST "system")) {
1029 prefer = XML_CATA_PREFER_SYSTEM;
1030 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1031 prefer = XML_CATA_PREFER_PUBLIC;
1032 } else {
1033 xmlGenericError(xmlGenericErrorContext,
1034 "Invalid value for prefer: '%s'\n", prop);
1035 }
1036 xmlFree(prop);
1037 }
1038 /*
1039 * Recurse to propagate prefer to the subtree
1040 * (xml:base handling is automated)
1041 */
1042 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1043 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1044 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001045 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001046 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1047 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001048 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001049 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1050 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1051 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001052 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001053 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1054 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1055 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001056 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001057 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1058 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1059 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001060 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001061 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1062 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1063 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001064 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001065 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1066 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1067 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001068 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001069 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1070 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1071 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
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 "nextCatalog")) {
1074 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1075 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001076 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001077 }
1078 if ((entry != NULL) && (parent != NULL)) {
1079 entry->parent = parent;
1080 if (parent->children == NULL)
1081 parent->children = entry;
1082 else {
1083 xmlCatalogEntryPtr prev;
1084
1085 prev = parent->children;
1086 while (prev->next != NULL)
1087 prev = prev->next;
1088 prev->next = entry;
1089 }
1090 }
1091 if (base != NULL)
1092 xmlFree(base);
1093 if (uri != NULL)
1094 xmlFree(uri);
1095 if (URL != NULL)
1096 xmlFree(URL);
1097}
1098
Daniel Veillard75b96822001-10-11 18:59:45 +00001099/**
1100 * xmlParseXMLCatalogNodeList:
1101 * @cur: the XML node list of siblings
1102 * @prefer: the PUBLIC vs. SYSTEM current preference value
1103 * @parent: the parent Catalog entry
1104 *
1105 * Examines a list of XML sibling nodes of a catalog and build
1106 * a list of Catalog entry from it adding it to the parent.
1107 * The examination will recurse to examine node subtrees.
1108 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001109static void
1110xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1111 xmlCatalogEntryPtr parent) {
1112 while (cur != NULL) {
1113 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1114 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1115 xmlParseXMLCatalogNode(cur, prefer, parent);
1116 }
1117 cur = cur->next;
1118 }
1119 /* TODO: sort the list according to REWRITE lengths and prefer value */
1120}
1121
Daniel Veillard75b96822001-10-11 18:59:45 +00001122/**
1123 * xmlParseXMLCatalog:
1124 * @value: the content in-memory of the catalog serialization
1125 * @prefer: the PUBLIC vs. SYSTEM current preference value
1126 * @file: the filename for the catalog
1127 *
1128 * Parses the catalog content to extract the XML tree and then analyze the
1129 * tree to build a list of Catalog entries corresponding to this catalog
1130 *
1131 * Returns the resulting Catalog entries list
1132 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001133static xmlCatalogEntryPtr
1134xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
1135 const char *file) {
1136 xmlDocPtr doc;
1137 xmlNodePtr cur;
1138 xmlChar *prop;
1139 xmlCatalogEntryPtr parent = NULL;
1140
1141 if ((value == NULL) || (file == NULL))
1142 return(NULL);
1143
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001144 if (xmlDebugCatalogs)
1145 xmlGenericError(xmlGenericErrorContext,
1146 "Parsing catalog %s's content\n", file);
1147
Daniel Veillard344cee72001-08-20 00:08:40 +00001148 doc = xmlParseDoc((xmlChar *) value);
1149 if (doc == NULL)
1150 return(NULL);
1151 doc->URL = xmlStrdup((const xmlChar *) file);
1152
1153 cur = xmlDocGetRootElement(doc);
1154 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1155 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1156 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1157
Daniel Veillard344cee72001-08-20 00:08:40 +00001158 prop = xmlGetProp(cur, BAD_CAST "prefer");
1159 if (prop != NULL) {
1160 if (xmlStrEqual(prop, BAD_CAST "system")) {
1161 prefer = XML_CATA_PREFER_SYSTEM;
1162 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1163 prefer = XML_CATA_PREFER_PUBLIC;
1164 } else {
1165 xmlGenericError(xmlGenericErrorContext,
1166 "Invalid value for prefer: '%s'\n",
1167 prop);
1168 }
1169 xmlFree(prop);
1170 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001171 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1172 (const xmlChar *)file, prefer);
1173 if (parent == NULL) {
1174 xmlFreeDoc(doc);
1175 return(NULL);
1176 }
1177
Daniel Veillard344cee72001-08-20 00:08:40 +00001178 cur = cur->children;
1179 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1180 } else {
1181 xmlGenericError(xmlGenericErrorContext,
1182 "File %s is not an XML Catalog\n", file);
1183 xmlFreeDoc(doc);
1184 return(NULL);
1185 }
1186 xmlFreeDoc(doc);
1187 return(parent);
1188}
1189
Daniel Veillard75b96822001-10-11 18:59:45 +00001190/**
1191 * xmlParseXMLCatalogFile:
1192 * @prefer: the PUBLIC vs. SYSTEM current preference value
1193 * @filename: the filename for the catalog
1194 *
1195 * Parses the catalog file to extract the XML tree and then analyze the
1196 * tree to build a list of Catalog entries corresponding to this catalog
1197 *
1198 * Returns the resulting Catalog entries list
1199 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001200static xmlCatalogEntryPtr
1201xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1202 xmlDocPtr doc;
1203 xmlNodePtr cur;
1204 xmlChar *prop;
1205 xmlCatalogEntryPtr parent = NULL;
1206
1207 if (filename == NULL)
1208 return(NULL);
1209
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001210 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001211 if (doc == NULL) {
1212 if (xmlDebugCatalogs)
1213 xmlGenericError(xmlGenericErrorContext,
1214 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001215 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001216 }
1217
1218 if (xmlDebugCatalogs)
1219 xmlGenericError(xmlGenericErrorContext,
1220 "Parsing catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001221
1222 cur = xmlDocGetRootElement(doc);
1223 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1224 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1225 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1226
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001227 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1228 (const xmlChar *)filename, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001229 if (parent == NULL) {
1230 xmlFreeDoc(doc);
1231 return(NULL);
1232 }
1233
1234 prop = xmlGetProp(cur, BAD_CAST "prefer");
1235 if (prop != NULL) {
1236 if (xmlStrEqual(prop, BAD_CAST "system")) {
1237 prefer = XML_CATA_PREFER_SYSTEM;
1238 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1239 prefer = XML_CATA_PREFER_PUBLIC;
1240 } else {
1241 xmlGenericError(xmlGenericErrorContext,
1242 "Invalid value for prefer: '%s'\n",
1243 prop);
1244 }
1245 xmlFree(prop);
1246 }
1247 cur = cur->children;
1248 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1249 } else {
1250 xmlGenericError(xmlGenericErrorContext,
1251 "File %s is not an XML Catalog\n", filename);
1252 xmlFreeDoc(doc);
1253 return(NULL);
1254 }
1255 xmlFreeDoc(doc);
1256 return(parent);
1257}
1258
Daniel Veillardcda96922001-08-21 10:56:31 +00001259/**
1260 * xmlFetchXMLCatalogFile:
1261 * @catal: an existing but incomplete catalog entry
1262 *
1263 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001264 *
1265 * Returns 0 in case of success, -1 otherwise
1266 */
1267static int
1268xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001269 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001270
1271 if (catal == NULL)
1272 return(-1);
1273 if (catal->value == NULL)
1274 return(-1);
1275 if (catal->children != NULL)
1276 return(-1);
1277
Daniel Veillard81463942001-10-16 12:34:39 +00001278 /*
1279 * lock the whole catalog for modification
1280 */
1281 xmlRMutexLock(xmlCatalogMutex);
1282 if (catal->children != NULL) {
1283 /* Okay someone else did it in the meantime */
1284 xmlRMutexUnlock(xmlCatalogMutex);
1285 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001286 }
1287
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001288 if (xmlCatalogXMLFiles != NULL) {
1289 doc = (xmlCatalogEntryPtr)
Daniel Veillard6990bf32001-08-23 21:17:48 +00001290 xmlHashLookup(xmlCatalogXMLFiles, catal->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001291 if (doc != NULL) {
1292 if (xmlDebugCatalogs)
1293 xmlGenericError(xmlGenericErrorContext,
1294 "Found %s in file hash\n", catal->value);
1295
1296 if (catal->type == XML_CATA_CATALOG)
1297 catal->children = doc->children;
1298 else
1299 catal->children = doc;
1300 catal->dealloc = 0;
1301 xmlRMutexUnlock(xmlCatalogMutex);
1302 return(0);
1303 }
1304 if (xmlDebugCatalogs)
1305 xmlGenericError(xmlGenericErrorContext,
1306 "%s not found in file hash\n", catal->value);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001307 }
1308
Daniel Veillardcda96922001-08-21 10:56:31 +00001309 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001310 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1311 * use the existing catalog, there is no recusivity allowed at
1312 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001313 */
Daniel Veillard6990bf32001-08-23 21:17:48 +00001314 doc = xmlParseXMLCatalogFile(catal->prefer, catal->value);
1315 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001316 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001317 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001318 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001319 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001320
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001321 if (catal->type == XML_CATA_CATALOG)
1322 catal->children = doc->children;
1323 else
1324 catal->children = doc;
1325
1326 doc->dealloc = 1;
1327
Daniel Veillard81463942001-10-16 12:34:39 +00001328 if (xmlCatalogXMLFiles == NULL)
1329 xmlCatalogXMLFiles = xmlHashCreate(10);
1330 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001331 if (xmlDebugCatalogs)
1332 xmlGenericError(xmlGenericErrorContext,
1333 "%s added to file hash\n", catal->value);
1334 xmlHashAddEntry(xmlCatalogXMLFiles, catal->value, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001335 }
Daniel Veillard81463942001-10-16 12:34:39 +00001336 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001337 return(0);
1338}
1339
Daniel Veillard75b96822001-10-11 18:59:45 +00001340/************************************************************************
1341 * *
1342 * XML Catalog handling *
1343 * *
1344 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001345
1346/**
1347 * xmlAddXMLCatalog:
1348 * @catal: top of an XML catalog
1349 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001350 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001351 * @replace: the replacement value for the match
1352 *
1353 * Add an entry in the XML catalog, it may overwrite existing but
1354 * different entries.
1355 *
1356 * Returns 0 if successful, -1 otherwise
1357 */
1358static int
1359xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1360 const xmlChar *orig, const xmlChar *replace) {
1361 xmlCatalogEntryPtr cur;
1362 xmlCatalogEntryType typ;
1363
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001364 if ((catal == NULL) ||
1365 ((catal->type != XML_CATA_CATALOG) &&
1366 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001367 return(-1);
1368 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001369 if (typ == XML_CATA_NONE) {
1370 if (xmlDebugCatalogs)
1371 xmlGenericError(xmlGenericErrorContext,
1372 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001373 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001374 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001375
1376 cur = catal->children;
1377 /*
1378 * Might be a simple "update in place"
1379 */
1380 if (cur != NULL) {
1381 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001382 if ((orig != NULL) && (cur->type == typ) &&
1383 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001384 if (xmlDebugCatalogs)
1385 xmlGenericError(xmlGenericErrorContext,
1386 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001387 if (cur->value != NULL)
1388 xmlFree(cur->value);
1389 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001390 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001391 }
1392 if (cur->next == NULL)
1393 break;
1394 cur = cur->next;
1395 }
1396 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001397 if (xmlDebugCatalogs)
1398 xmlGenericError(xmlGenericErrorContext,
1399 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001400 if (cur == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001401 catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001402 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001403 cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillardcda96922001-08-21 10:56:31 +00001404 return(0);
1405}
1406
1407/**
1408 * xmlDelXMLCatalog:
1409 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001410 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001411 *
1412 * Remove entries in the XML catalog where the value or the URI
1413 * is equal to @value
1414 *
1415 * Returns the number of entries removed if successful, -1 otherwise
1416 */
1417static int
1418xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1419 xmlCatalogEntryPtr cur, prev, tmp;
1420 int ret = 0;
1421
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001422 if ((catal == NULL) ||
1423 ((catal->type != XML_CATA_CATALOG) &&
1424 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001425 return(-1);
1426 if (value == NULL)
1427 return(-1);
1428
1429 /*
1430 * Scan the children
1431 */
1432 cur = catal->children;
1433 prev = NULL;
1434 while (cur != NULL) {
1435 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1436 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001437 if (xmlDebugCatalogs) {
1438 if (cur->name != NULL)
1439 xmlGenericError(xmlGenericErrorContext,
1440 "Removing element %s from catalog\n", cur->name);
1441 else
1442 xmlGenericError(xmlGenericErrorContext,
1443 "Removing element %s from catalog\n", cur->value);
1444 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001445 ret++;
1446 tmp = cur;
1447 cur = tmp->next;
1448 if (prev == NULL) {
1449 catal->children = cur;
1450 } else {
1451 prev->next = cur;
1452 }
1453 xmlFreeCatalogEntry(tmp);
1454 continue;
1455 }
1456 prev = cur;
1457 cur = cur->next;
1458 }
1459 return(ret);
1460}
1461
1462/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001463 * xmlCatalogXMLResolve:
1464 * @catal: a catalog list
1465 * @pubId: the public ID string
1466 * @sysId: the system ID string
1467 *
1468 * Do a complete resolution lookup of an External Identifier for a
1469 * list of catalog entries.
1470 *
1471 * Implements (or tries to) 7.1. External Identifier Resolution
1472 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1473 *
1474 * Returns the URI of the resource or NULL if not found
1475 */
1476static xmlChar *
1477xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1478 const xmlChar *sysID) {
1479 xmlChar *ret = NULL;
1480 xmlCatalogEntryPtr cur;
1481 int haveDelegate = 0;
1482 int haveNext = 0;
1483
1484 /*
1485 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1486 */
1487 if (sysID != NULL) {
1488 xmlCatalogEntryPtr rewrite = NULL;
1489 int lenrewrite = 0, len;
1490 cur = catal;
1491 haveDelegate = 0;
1492 while (cur != NULL) {
1493 switch (cur->type) {
1494 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001495 if (xmlStrEqual(sysID, cur->name)) {
1496 if (xmlDebugCatalogs)
1497 xmlGenericError(xmlGenericErrorContext,
1498 "Found system match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001499 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001500 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001501 break;
1502 case XML_CATA_REWRITE_SYSTEM:
1503 len = xmlStrlen(cur->name);
1504 if ((len > lenrewrite) &&
1505 (!xmlStrncmp(sysID, cur->name, len))) {
1506 lenrewrite = len;
1507 rewrite = cur;
1508 }
1509 break;
1510 case XML_CATA_DELEGATE_SYSTEM:
1511 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1512 haveDelegate++;
1513 break;
1514 case XML_CATA_NEXT_CATALOG:
1515 haveNext++;
1516 break;
1517 default:
1518 break;
1519 }
1520 cur = cur->next;
1521 }
1522 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001523 if (xmlDebugCatalogs)
1524 xmlGenericError(xmlGenericErrorContext,
1525 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001526 ret = xmlStrdup(rewrite->value);
1527 if (ret != NULL)
1528 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1529 return(ret);
1530 }
1531 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001532 const xmlChar *delegates[MAX_DELEGATE];
1533 int nbList = 0, i;
1534
Daniel Veillardcda96922001-08-21 10:56:31 +00001535 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001536 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001537 * matches when the list was produced.
1538 */
1539 cur = catal;
1540 while (cur != NULL) {
1541 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1542 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001543 for (i = 0;i < nbList;i++)
1544 if (xmlStrEqual(cur->value, delegates[i]))
1545 break;
1546 if (i < nbList) {
1547 cur = cur->next;
1548 continue;
1549 }
1550 if (nbList < MAX_DELEGATE)
1551 delegates[nbList++] = cur->value;
1552
Daniel Veillardcda96922001-08-21 10:56:31 +00001553 if (cur->children == NULL) {
1554 xmlFetchXMLCatalogFile(cur);
1555 }
1556 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001557 if (xmlDebugCatalogs)
1558 xmlGenericError(xmlGenericErrorContext,
1559 "Trying system delegate %s\n", cur->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001560 ret = xmlCatalogListXMLResolve(
1561 cur->children, NULL, sysID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001562 if (ret != NULL)
1563 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001564 }
1565 }
1566 cur = cur->next;
1567 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001568 /*
1569 * Apply the cut algorithm explained in 4/
1570 */
1571 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001572 }
1573 }
1574 /*
1575 * Then tries 5/ 6/ if a public ID is provided
1576 */
1577 if (pubID != NULL) {
1578 cur = catal;
1579 haveDelegate = 0;
1580 while (cur != NULL) {
1581 switch (cur->type) {
1582 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001583 if (xmlStrEqual(pubID, cur->name)) {
1584 if (xmlDebugCatalogs)
1585 xmlGenericError(xmlGenericErrorContext,
1586 "Found public match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001587 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001588 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001589 break;
1590 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001591 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1592 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001593 haveDelegate++;
1594 break;
1595 case XML_CATA_NEXT_CATALOG:
1596 if (sysID == NULL)
1597 haveNext++;
1598 break;
1599 default:
1600 break;
1601 }
1602 cur = cur->next;
1603 }
1604 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001605 const xmlChar *delegates[MAX_DELEGATE];
1606 int nbList = 0, i;
1607
Daniel Veillardcda96922001-08-21 10:56:31 +00001608 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001609 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001610 * matches when the list was produced.
1611 */
1612 cur = catal;
1613 while (cur != NULL) {
1614 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001615 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1616 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001617
1618 for (i = 0;i < nbList;i++)
1619 if (xmlStrEqual(cur->value, delegates[i]))
1620 break;
1621 if (i < nbList) {
1622 cur = cur->next;
1623 continue;
1624 }
1625 if (nbList < MAX_DELEGATE)
1626 delegates[nbList++] = cur->value;
1627
Daniel Veillardcda96922001-08-21 10:56:31 +00001628 if (cur->children == NULL) {
1629 xmlFetchXMLCatalogFile(cur);
1630 }
1631 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001632 if (xmlDebugCatalogs)
1633 xmlGenericError(xmlGenericErrorContext,
1634 "Trying public delegate %s\n", cur->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001635 ret = xmlCatalogListXMLResolve(
1636 cur->children, pubID, NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001637 if (ret != NULL)
1638 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001639 }
1640 }
1641 cur = cur->next;
1642 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001643 /*
1644 * Apply the cut algorithm explained in 4/
1645 */
1646 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001647 }
1648 }
1649 if (haveNext) {
1650 cur = catal;
1651 while (cur != NULL) {
1652 if (cur->type == XML_CATA_NEXT_CATALOG) {
1653 if (cur->children == NULL) {
1654 xmlFetchXMLCatalogFile(cur);
1655 }
1656 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001657 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1658 if (ret != NULL)
1659 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001660 }
1661 }
1662 cur = cur->next;
1663 }
1664 }
1665
1666 return(NULL);
1667}
1668
1669/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001670 * xmlCatalogXMLResolveURI:
1671 * @catal: a catalog list
1672 * @URI: the URI
1673 * @sysId: the system ID string
1674 *
1675 * Do a complete resolution lookup of an External Identifier for a
1676 * list of catalog entries.
1677 *
1678 * Implements (or tries to) 7.2.2. URI Resolution
1679 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1680 *
1681 * Returns the URI of the resource or NULL if not found
1682 */
1683static xmlChar *
1684xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1685 xmlChar *ret = NULL;
1686 xmlCatalogEntryPtr cur;
1687 int haveDelegate = 0;
1688 int haveNext = 0;
1689 xmlCatalogEntryPtr rewrite = NULL;
1690 int lenrewrite = 0, len;
1691
1692 if (catal == NULL)
1693 return(NULL);
1694
1695 if (URI == NULL)
1696 return(NULL);
1697
1698 /*
1699 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1700 */
1701 cur = catal;
1702 haveDelegate = 0;
1703 while (cur != NULL) {
1704 switch (cur->type) {
1705 case XML_CATA_URI:
1706 if (xmlStrEqual(URI, cur->name)) {
1707 if (xmlDebugCatalogs)
1708 xmlGenericError(xmlGenericErrorContext,
1709 "Found URI match %s\n", cur->name);
1710 return(xmlStrdup(cur->value));
1711 }
1712 break;
1713 case XML_CATA_REWRITE_URI:
1714 len = xmlStrlen(cur->name);
1715 if ((len > lenrewrite) &&
1716 (!xmlStrncmp(URI, cur->name, len))) {
1717 lenrewrite = len;
1718 rewrite = cur;
1719 }
1720 break;
1721 case XML_CATA_DELEGATE_URI:
1722 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1723 haveDelegate++;
1724 break;
1725 case XML_CATA_NEXT_CATALOG:
1726 haveNext++;
1727 break;
1728 default:
1729 break;
1730 }
1731 cur = cur->next;
1732 }
1733 if (rewrite != NULL) {
1734 if (xmlDebugCatalogs)
1735 xmlGenericError(xmlGenericErrorContext,
1736 "Using rewriting rule %s\n", rewrite->name);
1737 ret = xmlStrdup(rewrite->value);
1738 if (ret != NULL)
1739 ret = xmlStrcat(ret, &URI[lenrewrite]);
1740 return(ret);
1741 }
1742 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001743 const xmlChar *delegates[MAX_DELEGATE];
1744 int nbList = 0, i;
1745
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001746 /*
1747 * Assume the entries have been sorted by decreasing substring
1748 * matches when the list was produced.
1749 */
1750 cur = catal;
1751 while (cur != NULL) {
1752 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1753 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001754 for (i = 0;i < nbList;i++)
1755 if (xmlStrEqual(cur->value, delegates[i]))
1756 break;
1757 if (i < nbList) {
1758 cur = cur->next;
1759 continue;
1760 }
1761 if (nbList < MAX_DELEGATE)
1762 delegates[nbList++] = cur->value;
1763
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001764 if (cur->children == NULL) {
1765 xmlFetchXMLCatalogFile(cur);
1766 }
1767 if (cur->children != NULL) {
1768 if (xmlDebugCatalogs)
1769 xmlGenericError(xmlGenericErrorContext,
1770 "Trying URI delegate %s\n", cur->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001771 ret = xmlCatalogListXMLResolveURI(
1772 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001773 if (ret != NULL)
1774 return(ret);
1775 }
1776 }
1777 cur = cur->next;
1778 }
1779 /*
1780 * Apply the cut algorithm explained in 4/
1781 */
1782 return(XML_CATAL_BREAK);
1783 }
1784 if (haveNext) {
1785 cur = catal;
1786 while (cur != NULL) {
1787 if (cur->type == XML_CATA_NEXT_CATALOG) {
1788 if (cur->children == NULL) {
1789 xmlFetchXMLCatalogFile(cur);
1790 }
1791 if (cur->children != NULL) {
1792 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1793 if (ret != NULL)
1794 return(ret);
1795 }
1796 }
1797 cur = cur->next;
1798 }
1799 }
1800
1801 return(NULL);
1802}
1803
1804/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001805 * xmlCatalogListXMLResolve:
1806 * @catal: a catalog list
1807 * @pubId: the public ID string
1808 * @sysId: the system ID string
1809 *
1810 * Do a complete resolution lookup of an External Identifier for a
1811 * list of catalogs
1812 *
1813 * Implements (or tries to) 7.1. External Identifier Resolution
1814 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1815 *
1816 * Returns the URI of the resource or NULL if not found
1817 */
1818static xmlChar *
1819xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1820 const xmlChar *sysID) {
1821 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001822 xmlChar *urnID = NULL;
1823
1824 if (catal == NULL)
1825 return(NULL);
1826 if ((pubID == NULL) && (sysID == NULL))
1827 return(NULL);
1828
1829 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1830 urnID = xmlCatalogUnWrapURN(pubID);
1831 if (xmlDebugCatalogs) {
1832 if (urnID == NULL)
1833 xmlGenericError(xmlGenericErrorContext,
1834 "Public URN ID %s expanded to NULL\n", pubID);
1835 else
1836 xmlGenericError(xmlGenericErrorContext,
1837 "Public URN ID expanded to %s\n", urnID);
1838 }
1839 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1840 if (urnID != NULL)
1841 xmlFree(urnID);
1842 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001843 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001844 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1845 urnID = xmlCatalogUnWrapURN(sysID);
1846 if (xmlDebugCatalogs) {
1847 if (urnID == NULL)
1848 xmlGenericError(xmlGenericErrorContext,
1849 "System URN ID %s expanded to NULL\n", sysID);
1850 else
1851 xmlGenericError(xmlGenericErrorContext,
1852 "System URN ID expanded to %s\n", urnID);
1853 }
1854 if (pubID == NULL)
1855 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1856 else if (xmlStrEqual(pubID, urnID))
1857 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1858 else {
1859 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1860 }
1861 if (urnID != NULL)
1862 xmlFree(urnID);
1863 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001864 }
1865 while (catal != NULL) {
1866 if (catal->type == XML_CATA_CATALOG) {
1867 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001868 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001869 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001870 if (catal->children != NULL) {
1871 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1872 if (ret != NULL)
1873 return(ret);
1874 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001875 }
1876 catal = catal->next;
1877 }
1878 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001879}
1880
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001881/**
1882 * xmlCatalogListXMLResolveURI:
1883 * @catal: a catalog list
1884 * @URI: the URI
1885 *
1886 * Do a complete resolution lookup of an URI for a list of catalogs
1887 *
1888 * Implements (or tries to) 7.2. URI Resolution
1889 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1890 *
1891 * Returns the URI of the resource or NULL if not found
1892 */
1893static xmlChar *
1894xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1895 xmlChar *ret = NULL;
1896 xmlChar *urnID = NULL;
1897
1898 if (catal == NULL)
1899 return(NULL);
1900 if (URI == NULL)
1901 return(NULL);
1902
1903 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1904 urnID = xmlCatalogUnWrapURN(URI);
1905 if (xmlDebugCatalogs) {
1906 if (urnID == NULL)
1907 xmlGenericError(xmlGenericErrorContext,
1908 "URN ID %s expanded to NULL\n", URI);
1909 else
1910 xmlGenericError(xmlGenericErrorContext,
1911 "URN ID expanded to %s\n", urnID);
1912 }
1913 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1914 if (urnID != NULL)
1915 xmlFree(urnID);
1916 return(ret);
1917 }
1918 while (catal != NULL) {
1919 if (catal->type == XML_CATA_CATALOG) {
1920 if (catal->children == NULL) {
1921 xmlFetchXMLCatalogFile(catal);
1922 }
1923 if (catal->children != NULL) {
1924 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1925 if (ret != NULL)
1926 return(ret);
1927 }
1928 }
1929 catal = catal->next;
1930 }
1931 return(ret);
1932}
1933
Daniel Veillard344cee72001-08-20 00:08:40 +00001934/************************************************************************
1935 * *
1936 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001937 * *
1938 ************************************************************************/
1939
1940
1941#define RAW *cur
1942#define NEXT cur++;
1943#define SKIP(x) cur += x;
1944
1945#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1946
Daniel Veillard75b96822001-10-11 18:59:45 +00001947/**
1948 * xmlParseSGMLCatalogComment:
1949 * @cur: the current character
1950 *
1951 * Skip a comment in an SGML catalog
1952 *
1953 * Returns new current character
1954 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001955static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001956xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001957 if ((cur[0] != '-') || (cur[1] != '-'))
1958 return(cur);
1959 SKIP(2);
1960 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1961 NEXT;
1962 if (cur[0] == 0) {
1963 return(NULL);
1964 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001965 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001966}
1967
Daniel Veillard75b96822001-10-11 18:59:45 +00001968/**
1969 * xmlParseSGMLCatalogPubid:
1970 * @cur: the current character
1971 * @id: the return location
1972 *
1973 * Parse an SGML catalog ID
1974 *
1975 * Returns new current character and store the value in @id
1976 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001977static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001978xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001979 xmlChar *buf = NULL;
1980 int len = 0;
1981 int size = 50;
1982 xmlChar stop;
1983 int count = 0;
1984
1985 *id = NULL;
1986
1987 if (RAW == '"') {
1988 NEXT;
1989 stop = '"';
1990 } else if (RAW == '\'') {
1991 NEXT;
1992 stop = '\'';
1993 } else {
1994 stop = ' ';
1995 }
1996 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1997 if (buf == NULL) {
1998 xmlGenericError(xmlGenericErrorContext,
1999 "malloc of %d byte failed\n", size);
2000 return(NULL);
2001 }
2002 while (xmlIsPubidChar(*cur)) {
2003 if ((*cur == stop) && (stop != ' '))
2004 break;
2005 if ((stop == ' ') && (IS_BLANK(*cur)))
2006 break;
2007 if (len + 1 >= size) {
2008 size *= 2;
2009 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2010 if (buf == NULL) {
2011 xmlGenericError(xmlGenericErrorContext,
2012 "realloc of %d byte failed\n", size);
2013 return(NULL);
2014 }
2015 }
2016 buf[len++] = *cur;
2017 count++;
2018 NEXT;
2019 }
2020 buf[len] = 0;
2021 if (stop == ' ') {
2022 if (!IS_BLANK(*cur)) {
2023 xmlFree(buf);
2024 return(NULL);
2025 }
2026 } else {
2027 if (*cur != stop) {
2028 xmlFree(buf);
2029 return(NULL);
2030 }
2031 NEXT;
2032 }
2033 *id = buf;
2034 return(cur);
2035}
2036
Daniel Veillard75b96822001-10-11 18:59:45 +00002037/**
2038 * xmlParseSGMLCatalogName:
2039 * @cur: the current character
2040 * @name: the return location
2041 *
2042 * Parse an SGML catalog name
2043 *
2044 * Returns new current character and store the value in @name
2045 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002046static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002047xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002048 xmlChar buf[XML_MAX_NAMELEN + 5];
2049 int len = 0;
2050 int c;
2051
2052 *name = NULL;
2053
2054 /*
2055 * Handler for more complex cases
2056 */
2057 c = *cur;
2058 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2059 return(NULL);
2060 }
2061
2062 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2063 (c == '.') || (c == '-') ||
2064 (c == '_') || (c == ':'))) {
2065 buf[len++] = c;
2066 cur++;
2067 c = *cur;
2068 if (len >= XML_MAX_NAMELEN)
2069 return(NULL);
2070 }
2071 *name = xmlStrndup(buf, len);
2072 return(cur);
2073}
2074
Daniel Veillard75b96822001-10-11 18:59:45 +00002075/**
2076 * xmlGetSGMLCatalogEntryType:
2077 * @name: the entry name
2078 *
2079 * Get the Catalog entry type for a given SGML Catalog name
2080 *
2081 * Returns Catalog entry type
2082 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002083static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002084xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002085 xmlCatalogEntryType type = XML_CATA_NONE;
2086 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2087 type = SGML_CATA_SYSTEM;
2088 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2089 type = SGML_CATA_PUBLIC;
2090 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2091 type = SGML_CATA_DELEGATE;
2092 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2093 type = SGML_CATA_ENTITY;
2094 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2095 type = SGML_CATA_DOCTYPE;
2096 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2097 type = SGML_CATA_LINKTYPE;
2098 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2099 type = SGML_CATA_NOTATION;
2100 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2101 type = SGML_CATA_SGMLDECL;
2102 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2103 type = SGML_CATA_DOCUMENT;
2104 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2105 type = SGML_CATA_CATALOG;
2106 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2107 type = SGML_CATA_BASE;
2108 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2109 type = SGML_CATA_DELEGATE;
2110 return(type);
2111}
2112
Daniel Veillard75b96822001-10-11 18:59:45 +00002113/**
2114 * xmlParseSGMLCatalog:
2115 * @catal: the SGML Catalog
2116 * @value: the content of the SGML Catalog serialization
2117 * @file: the filepath for the catalog
2118 * @super: should this be handled as a Super Catalog in which case
2119 * parsing is not recursive
2120 *
2121 * Parse an SGML catalog content and fill up the @catal hash table with
2122 * the new entries found.
2123 *
2124 * Returns 0 in case of success, -1 in case of error.
2125 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002126static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002127xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2128 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002129 const xmlChar *cur = value;
2130 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002131 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002132
2133 if ((cur == NULL) || (file == NULL))
2134 return(-1);
2135 base = xmlStrdup((const xmlChar *) file);
2136
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002137 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002138 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002139 if (cur[0] == 0)
2140 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002141 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002142 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002143 if (cur == NULL) {
2144 /* error */
2145 break;
2146 }
2147 } else {
2148 xmlChar *sysid = NULL;
2149 xmlChar *name = NULL;
2150 xmlCatalogEntryType type = XML_CATA_NONE;
2151
Daniel Veillardcda96922001-08-21 10:56:31 +00002152 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002153 if (name == NULL) {
2154 /* error */
2155 break;
2156 }
2157 if (!IS_BLANK(*cur)) {
2158 /* error */
2159 break;
2160 }
2161 SKIP_BLANKS;
2162 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002163 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002164 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002165 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002166 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002167 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002168 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002169 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002170 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002171 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002172 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002173 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002174 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002175 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002176 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002177 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002178 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002179 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002180 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002181 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002182 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002183 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002184 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002185 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002186 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2187 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002188 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002189 if (name == NULL) {
2190 /* error */
2191 break;
2192 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002193 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002194 continue;
2195 }
2196 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002197 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002198
2199 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002200 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002201 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002202 type = SGML_CATA_PENTITY;
2203 case SGML_CATA_PENTITY:
2204 case SGML_CATA_DOCTYPE:
2205 case SGML_CATA_LINKTYPE:
2206 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002207 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002208 if (cur == NULL) {
2209 /* error */
2210 break;
2211 }
2212 if (!IS_BLANK(*cur)) {
2213 /* error */
2214 break;
2215 }
2216 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002217 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002218 if (cur == NULL) {
2219 /* error */
2220 break;
2221 }
2222 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002223 case SGML_CATA_PUBLIC:
2224 case SGML_CATA_SYSTEM:
2225 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002226 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002227 if (cur == NULL) {
2228 /* error */
2229 break;
2230 }
2231 if (!IS_BLANK(*cur)) {
2232 /* error */
2233 break;
2234 }
2235 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002236 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002237 if (cur == NULL) {
2238 /* error */
2239 break;
2240 }
2241 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002242 case SGML_CATA_BASE:
2243 case SGML_CATA_CATALOG:
2244 case SGML_CATA_DOCUMENT:
2245 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002246 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002247 if (cur == NULL) {
2248 /* error */
2249 break;
2250 }
2251 break;
2252 default:
2253 break;
2254 }
2255 if (cur == NULL) {
2256 if (name != NULL)
2257 xmlFree(name);
2258 if (sysid != NULL)
2259 xmlFree(sysid);
2260 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002261 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002262 if (base != NULL)
2263 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002264 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002265 } else if ((type == SGML_CATA_PUBLIC) ||
2266 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002267 xmlChar *filename;
2268
2269 filename = xmlBuildURI(sysid, base);
2270 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002271 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002272
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002273 entry = xmlNewCatalogEntry(type, name, filename,
2274 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002275 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002276 if (res < 0) {
2277 xmlFreeCatalogEntry(entry);
2278 }
2279 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002280 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002281
Daniel Veillard344cee72001-08-20 00:08:40 +00002282 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002283 if (super) {
2284 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002285
Daniel Veillard82d75332001-10-08 15:01:59 +00002286 entry = xmlNewCatalogEntry(type, sysid, NULL,
2287 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002288 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002289 if (res < 0) {
2290 xmlFreeCatalogEntry(entry);
2291 }
2292 } else {
2293 xmlChar *filename;
2294
2295 filename = xmlBuildURI(sysid, base);
2296 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002297 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002298 xmlFree(filename);
2299 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002300 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002301 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002302 /*
2303 * drop anything else we won't handle it
2304 */
2305 if (name != NULL)
2306 xmlFree(name);
2307 if (sysid != NULL)
2308 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002309 }
2310 }
2311 if (base != NULL)
2312 xmlFree(base);
2313 if (cur == NULL)
2314 return(-1);
2315 return(0);
2316}
2317
Daniel Veillard75b96822001-10-11 18:59:45 +00002318/************************************************************************
2319 * *
2320 * SGML Catalog handling *
2321 * *
2322 ************************************************************************/
2323
Daniel Veillardcda96922001-08-21 10:56:31 +00002324/**
2325 * xmlCatalogGetSGMLPublic:
2326 * @catal: an SGML catalog hash
2327 * @pubId: the public ID string
2328 *
2329 * Try to lookup the system ID associated to a public ID
2330 *
2331 * Returns the system ID if found or NULL otherwise.
2332 */
2333static const xmlChar *
2334xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2335 xmlCatalogEntryPtr entry;
2336
2337 if (catal == NULL)
2338 return(NULL);
2339
2340 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2341 if (entry == NULL)
2342 return(NULL);
2343 if (entry->type == SGML_CATA_PUBLIC)
2344 return(entry->value);
2345 return(NULL);
2346}
2347
2348/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002349 * xmlCatalogGetSGMLSystem:
2350 * @catal: an SGML catalog hash
2351 * @sysId: the public ID string
2352 *
2353 * Try to lookup the catalog local reference for a system ID
2354 *
2355 * Returns the system ID if found or NULL otherwise.
2356 */
2357static const xmlChar *
2358xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2359 xmlCatalogEntryPtr entry;
2360
2361 if (catal == NULL)
2362 return(NULL);
2363
2364 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2365 if (entry == NULL)
2366 return(NULL);
2367 if (entry->type == SGML_CATA_SYSTEM)
2368 return(entry->value);
2369 return(NULL);
2370}
2371
2372/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002373 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002374 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002375 * @pubId: the public ID string
2376 * @sysId: the system ID string
2377 *
2378 * Do a complete resolution lookup of an External Identifier
2379 *
2380 * Returns the URI of the resource or NULL if not found
2381 */
2382static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002383xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2384 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002385 const xmlChar *ret = NULL;
2386
Daniel Veillard75b96822001-10-11 18:59:45 +00002387 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002388 return(NULL);
2389
2390 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002391 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002392 if (ret != NULL)
2393 return(ret);
2394 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002395 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002396 return(NULL);
2397}
2398
Daniel Veillarda7374592001-05-10 14:17:55 +00002399/************************************************************************
2400 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002401 * Specific Public interfaces *
2402 * *
2403 ************************************************************************/
2404
2405/**
2406 * xmlLoadSGMLSuperCatalog:
2407 * @filename: a file path
2408 *
2409 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2410 * references. This is only needed for manipulating SGML Super Catalogs
2411 * like adding and removing CATALOG or DELEGATE entries.
2412 *
2413 * Returns the catalog parsed or NULL in case of error
2414 */
2415xmlCatalogPtr
2416xmlLoadSGMLSuperCatalog(const char *filename)
2417{
2418 xmlChar *content;
2419 xmlCatalogPtr catal;
2420 int ret;
2421
2422 content = xmlLoadFileContent(filename);
2423 if (content == NULL)
2424 return(NULL);
2425
2426 catal = xmlNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2427 if (catal == NULL) {
2428 xmlFree(content);
2429 return(NULL);
2430 }
2431
2432 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2433 xmlFree(content);
2434 if (ret < 0) {
2435 xmlFreeCatalog(catal);
2436 return(NULL);
2437 }
2438 return (catal);
2439}
2440
2441/**
2442 * xmlLoadACatalog:
2443 * @filename: a file path
2444 *
2445 * Load the catalog and build the associated data structures.
2446 * This can be either an XML Catalog or an SGML Catalog
2447 * It will recurse in SGML CATALOG entries. On the other hand XML
2448 * Catalogs are not handled recursively.
2449 *
2450 * Returns the catalog parsed or NULL in case of error
2451 */
2452xmlCatalogPtr
2453xmlLoadACatalog(const char *filename)
2454{
2455 xmlChar *content;
2456 xmlChar *first;
2457 xmlCatalogPtr catal;
2458 int ret;
2459
2460 content = xmlLoadFileContent(filename);
2461 if (content == NULL)
2462 return(NULL);
2463
2464
2465 first = content;
2466
2467 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2468 (!(((*first >= 'A') && (*first <= 'Z')) ||
2469 ((*first >= 'a') && (*first <= 'z')))))
2470 first++;
2471
2472 if (*first != '<') {
2473 catal = xmlNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2474 if (catal == NULL) {
2475 xmlFree(content);
2476 return(NULL);
2477 }
2478 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2479 if (ret < 0) {
2480 xmlFreeCatalog(catal);
2481 xmlFree(content);
2482 return(NULL);
2483 }
2484 } else {
2485 catal = xmlNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2486 if (catal == NULL) {
2487 xmlFree(content);
2488 return(NULL);
2489 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002490 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG,
2491 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002492 }
2493 xmlFree(content);
2494 return (catal);
2495}
2496
2497/**
2498 * xmlExpandCatalog:
2499 * @catal: a catalog
2500 * @filename: a file path
2501 *
2502 * Load the catalog and expand the existing catal structure.
2503 * This can be either an XML Catalog or an SGML Catalog
2504 *
2505 * Returns 0 in case of success, -1 in case of error
2506 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002507static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002508xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2509{
Daniel Veillard75b96822001-10-11 18:59:45 +00002510 int ret;
2511
2512 if ((catal == NULL) || (filename == NULL))
2513 return(-1);
2514
Daniel Veillard75b96822001-10-11 18:59:45 +00002515
2516 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002517 xmlChar *content;
2518
2519 content = xmlLoadFileContent(filename);
2520 if (content == NULL)
2521 return(-1);
2522
Daniel Veillard75b96822001-10-11 18:59:45 +00002523 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2524 if (ret < 0) {
2525 xmlFree(content);
2526 return(-1);
2527 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002528 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002529 } else {
2530 xmlCatalogEntryPtr tmp, cur;
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002531 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG,
2532 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002533
Daniel Veillard75b96822001-10-11 18:59:45 +00002534 cur = catal->xml;
2535 if (cur == NULL) {
2536 catal->xml = tmp;
2537 } else {
2538 while (cur->next != NULL) cur = cur->next;
2539 cur->next = tmp;
2540 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002541 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002542 return (0);
2543}
2544
2545/**
2546 * xmlACatalogResolveSystem:
2547 * @catal: a Catalog
2548 * @sysId: the public ID string
2549 *
2550 * Try to lookup the catalog resource for a system ID
2551 *
2552 * Returns the system ID if found or NULL otherwise, the value returned
2553 * must be freed by the caller.
2554 */
2555xmlChar *
2556xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2557 xmlChar *ret = NULL;
2558
2559 if ((sysID == NULL) || (catal == NULL))
2560 return(NULL);
2561
2562 if (xmlDebugCatalogs)
2563 xmlGenericError(xmlGenericErrorContext,
2564 "Resolve sysID %s\n", sysID);
2565
2566 if (catal->type == XML_XML_CATALOG_TYPE) {
2567 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2568 if (ret == XML_CATAL_BREAK)
2569 ret = NULL;
2570 } else {
2571 const xmlChar *sgml;
2572
2573 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2574 if (sgml != NULL)
2575 ret = xmlStrdup(sgml);
2576 }
2577 return(ret);
2578}
2579
2580/**
2581 * xmlACatalogResolvePublic:
2582 * @catal: a Catalog
2583 * @pubId: the public ID string
2584 *
2585 * Try to lookup the system ID associated to a public ID in that catalog
2586 *
2587 * Returns the system ID if found or NULL otherwise, the value returned
2588 * must be freed by the caller.
2589 */
2590xmlChar *
2591xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2592 xmlChar *ret = NULL;
2593
2594 if ((pubID == NULL) || (catal == NULL))
2595 return(NULL);
2596
2597 if (xmlDebugCatalogs)
2598 xmlGenericError(xmlGenericErrorContext,
2599 "Resolve pubID %s\n", pubID);
2600
2601 if (catal->type == XML_XML_CATALOG_TYPE) {
2602 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2603 if (ret == XML_CATAL_BREAK)
2604 ret = NULL;
2605 } else {
2606 const xmlChar *sgml;
2607
2608 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2609 if (sgml != NULL)
2610 ret = xmlStrdup(sgml);
2611 }
2612 return(ret);
2613}
2614
2615/**
2616 * xmlACatalogResolve:
2617 * @catal: a Catalog
2618 * @pubId: the public ID string
2619 * @sysId: the system ID string
2620 *
2621 * Do a complete resolution lookup of an External Identifier
2622 *
2623 * Returns the URI of the resource or NULL if not found, it must be freed
2624 * by the caller.
2625 */
2626xmlChar *
2627xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2628 const xmlChar * sysID)
2629{
2630 xmlChar *ret = NULL;
2631
2632 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2633 return (NULL);
2634
2635 if (xmlDebugCatalogs) {
2636 if (pubID != NULL) {
2637 xmlGenericError(xmlGenericErrorContext,
2638 "Resolve: pubID %s\n", pubID);
2639 } else {
2640 xmlGenericError(xmlGenericErrorContext,
2641 "Resolve: sysID %s\n", sysID);
2642 }
2643 }
2644
2645 if (catal->type == XML_XML_CATALOG_TYPE) {
2646 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2647 if (ret == XML_CATAL_BREAK)
2648 ret = NULL;
2649 } else {
2650 const xmlChar *sgml;
2651
2652 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2653 if (sgml != NULL)
2654 ret = xmlStrdup(sgml);
2655 }
2656 return (ret);
2657}
2658
2659/**
2660 * xmlACatalogResolveURI:
2661 * @catal: a Catalog
2662 * @pubId: the URI
2663 *
2664 * Do a complete resolution lookup of an URI
2665 *
2666 * Returns the URI of the resource or NULL if not found, it must be freed
2667 * by the caller.
2668 */
2669xmlChar *
2670xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2671 xmlChar *ret = NULL;
2672
2673 if ((URI == NULL) || (catal == NULL))
2674 return(NULL);
2675
Daniel Veillardb44025c2001-10-11 22:55:55 +00002676 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002677 xmlGenericError(xmlGenericErrorContext,
2678 "Resolve URI %s\n", URI);
2679
2680 if (catal->type == XML_XML_CATALOG_TYPE) {
2681 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2682 if (ret == XML_CATAL_BREAK)
2683 ret = NULL;
2684 } else {
2685 const xmlChar *sgml;
2686
2687 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2688 if (sgml != NULL)
2689 sgml = xmlStrdup(sgml);
2690 }
2691 return(ret);
2692}
2693
2694/**
2695 * xmlACatalogDump:
2696 * @catal: a Catalog
2697 * @out: the file.
2698 *
2699 * Free up all the memory associated with catalogs
2700 */
2701void
2702xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
2703 if (out == NULL)
2704 return;
2705
2706 if (catal->type == XML_XML_CATALOG_TYPE) {
2707 xmlDumpXMLCatalog(out, catal->xml);
2708 } else {
2709 xmlHashScan(catal->sgml,
2710 (xmlHashScanner) xmlCatalogDumpEntry, out);
2711 }
2712}
2713
2714/**
2715 * xmlACatalogAdd:
2716 * @catal: a Catalog
2717 * @type: the type of record to add to the catalog
2718 * @orig: the system, public or prefix to match
2719 * @replace: the replacement value for the match
2720 *
2721 * Add an entry in the catalog, it may overwrite existing but
2722 * different entries.
2723 *
2724 * Returns 0 if successful, -1 otherwise
2725 */
2726int
2727xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2728 const xmlChar * orig, const xmlChar * replace)
2729{
2730 int res = -1;
2731
2732 if (catal == NULL)
2733 return(-1);
2734
2735 if (catal->type == XML_XML_CATALOG_TYPE) {
2736 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2737 } else {
2738 xmlCatalogEntryType cattype;
2739
2740 cattype = xmlGetSGMLCatalogEntryType(type);
2741 if (cattype != XML_CATA_NONE) {
2742 xmlCatalogEntryPtr entry;
2743
2744 entry = xmlNewCatalogEntry(cattype, orig, replace,
2745 XML_CATA_PREFER_NONE);
2746 res = xmlHashAddEntry(catal->sgml, orig, entry);
2747 }
2748 }
2749 return (res);
2750}
2751
2752/**
2753 * xmlACatalogRemove:
2754 * @catal: a Catalog
2755 * @value: the value to remove
2756 *
2757 * Remove an entry from the catalog
2758 *
2759 * Returns the number of entries removed if successful, -1 otherwise
2760 */
2761int
2762xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2763 int res = -1;
2764
2765 if ((catal == NULL) || (value == NULL))
2766 return(-1);
2767
2768 if (catal->type == XML_XML_CATALOG_TYPE) {
2769 res = xmlDelXMLCatalog(catal->xml, value);
2770 } else {
2771 res = xmlHashRemoveEntry(catal->sgml, value,
2772 (xmlHashDeallocator) xmlFreeCatalogEntry);
2773 if (res == 0)
2774 res = 1;
2775 }
2776 return(res);
2777}
2778
2779/************************************************************************
2780 * *
2781 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002782 * *
2783 ************************************************************************/
2784
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002785/**
Daniel Veillard81463942001-10-16 12:34:39 +00002786 * xmlInitializeCatalogData:
2787 *
2788 * Do the catalog initialization only of global data, doesn't try to load
2789 * any catalog actually.
2790 * this function is not thread safe, catalog initialization should
2791 * preferably be done once at startup
2792 */
2793static void
2794xmlInitializeCatalogData(void) {
2795 if (xmlCatalogInitialized != 0)
2796 return;
2797
2798 if (getenv("XML_DEBUG_CATALOG"))
2799 xmlDebugCatalogs = 1;
2800 xmlCatalogMutex = xmlNewRMutex();
2801
2802 xmlCatalogInitialized = 1;
2803}
2804/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002805 * xmlInitializeCatalog:
2806 *
2807 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002808 * this function is not thread safe, catalog initialization should
2809 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002810 */
2811void
2812xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002813 if (xmlCatalogInitialized != 0)
2814 return;
2815
Daniel Veillard81463942001-10-16 12:34:39 +00002816 xmlInitializeCatalogData();
2817 xmlRMutexLock(xmlCatalogMutex);
2818
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002819 if (getenv("XML_DEBUG_CATALOG"))
2820 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002821
Daniel Veillard75b96822001-10-11 18:59:45 +00002822 if (xmlDefaultCatalog == NULL) {
2823 const char *catalogs;
2824 xmlCatalogPtr catal;
2825
Daniel Veillardb44025c2001-10-11 22:55:55 +00002826 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002827 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002828 catalogs = XML_XML_DEFAULT_CATALOG;
2829
2830 catal = xmlNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002831 if (catal != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002832
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002833 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002834 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002835
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002836 xmlDefaultCatalog = catal;
2837 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002838 }
2839
Daniel Veillard81463942001-10-16 12:34:39 +00002840 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002841}
2842
Daniel Veillard82d75332001-10-08 15:01:59 +00002843
2844/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002845 * xmlLoadCatalog:
2846 * @filename: a file path
2847 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002848 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002849 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002850 * this function is not thread safe, catalog initialization should
2851 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002852 *
2853 * Returns 0 in case of success -1 in case of error
2854 */
2855int
Daniel Veillard16756b62001-10-01 07:36:25 +00002856xmlLoadCatalog(const char *filename)
2857{
Daniel Veillard75b96822001-10-11 18:59:45 +00002858 int ret;
2859 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002860
Daniel Veillard81463942001-10-16 12:34:39 +00002861 if (!xmlCatalogInitialized)
2862 xmlInitializeCatalogData();
2863
2864 xmlRMutexLock(xmlCatalogMutex);
2865
Daniel Veillard75b96822001-10-11 18:59:45 +00002866 if (xmlDefaultCatalog == NULL) {
2867 catal = xmlLoadACatalog(filename);
2868 if (catal == NULL)
2869 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002870
Daniel Veillard75b96822001-10-11 18:59:45 +00002871 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002872 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002873 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002874 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002875
Daniel Veillard75b96822001-10-11 18:59:45 +00002876 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002877 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002878 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002879}
2880
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002881/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002882 * xmlLoadCatalogs:
2883 * @paths: a list of file path separated by ':' or spaces
2884 *
2885 * Load the catalogs and makes their definitions effective for the default
2886 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002887 * this function is not thread safe, catalog initialization should
2888 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002889 */
2890void
2891xmlLoadCatalogs(const char *pathss) {
2892 const char *cur;
2893 const char *paths;
2894 xmlChar *path;
2895
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002896 if (pathss == NULL)
2897 return;
2898
Daniel Veillard81418e32001-05-22 15:08:55 +00002899 cur = pathss;
2900 while ((cur != NULL) && (*cur != 0)) {
2901 while (IS_BLANK(*cur)) cur++;
2902 if (*cur != 0) {
2903 paths = cur;
2904 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2905 cur++;
2906 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2907 if (path != NULL) {
2908 xmlLoadCatalog((const char *) path);
2909 xmlFree(path);
2910 }
2911 }
2912 while (*cur == ':')
2913 cur++;
2914 }
2915}
2916
Daniel Veillarda7374592001-05-10 14:17:55 +00002917/**
2918 * xmlCatalogCleanup:
2919 *
2920 * Free up all the memory associated with catalogs
2921 */
2922void
2923xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00002924 if (xmlCatalogInitialized == 0)
2925 return;
2926
Daniel Veillard81463942001-10-16 12:34:39 +00002927 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002928 if (xmlDebugCatalogs)
2929 xmlGenericError(xmlGenericErrorContext,
2930 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002931 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002932 xmlHashFree(xmlCatalogXMLFiles,
2933 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002934 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002935 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002936 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002937 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002938 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002939 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00002940 xmlRMutexUnlock(xmlCatalogMutex);
2941 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00002942}
2943
2944/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002945 * xmlCatalogResolveSystem:
2946 * @sysId: the public ID string
2947 *
2948 * Try to lookup the catalog resource for a system ID
2949 *
2950 * Returns the system ID if found or NULL otherwise, the value returned
2951 * must be freed by the caller.
2952 */
2953xmlChar *
2954xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002955 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002956
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002957 if (!xmlCatalogInitialized)
2958 xmlInitializeCatalog();
2959
Daniel Veillard75b96822001-10-11 18:59:45 +00002960 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
2961 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002962}
2963
2964/**
2965 * xmlCatalogResolvePublic:
2966 * @pubId: the public ID string
2967 *
2968 * Try to lookup the system ID associated to a public ID
2969 *
2970 * Returns the system ID if found or NULL otherwise, the value returned
2971 * must be freed by the caller.
2972 */
2973xmlChar *
2974xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002975 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002976
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002977 if (!xmlCatalogInitialized)
2978 xmlInitializeCatalog();
2979
Daniel Veillard75b96822001-10-11 18:59:45 +00002980 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
2981 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002982}
Daniel Veillard344cee72001-08-20 00:08:40 +00002983
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002984/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002985 * xmlCatalogResolve:
2986 * @pubId: the public ID string
2987 * @sysId: the system ID string
2988 *
2989 * Do a complete resolution lookup of an External Identifier
2990 *
2991 * Returns the URI of the resource or NULL if not found, it must be freed
2992 * by the caller.
2993 */
2994xmlChar *
2995xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002996 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002997
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002998 if (!xmlCatalogInitialized)
2999 xmlInitializeCatalog();
3000
Daniel Veillard75b96822001-10-11 18:59:45 +00003001 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3002 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003003}
3004
3005/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003006 * xmlCatalogResolveURI:
3007 * @pubId: the URI
3008 *
3009 * Do a complete resolution lookup of an URI
3010 *
3011 * Returns the URI of the resource or NULL if not found, it must be freed
3012 * by the caller.
3013 */
3014xmlChar *
3015xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003016 xmlChar *ret;
3017
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003018 if (!xmlCatalogInitialized)
3019 xmlInitializeCatalog();
3020
Daniel Veillard75b96822001-10-11 18:59:45 +00003021 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3022 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003023}
3024
3025/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003026 * xmlCatalogDump:
3027 * @out: the file.
3028 *
3029 * Free up all the memory associated with catalogs
3030 */
3031void
3032xmlCatalogDump(FILE *out) {
3033 if (out == NULL)
3034 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003035
Daniel Veillard75b96822001-10-11 18:59:45 +00003036 if (!xmlCatalogInitialized)
3037 xmlInitializeCatalog();
3038
3039 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003040}
3041
3042/**
3043 * xmlCatalogAdd:
3044 * @type: the type of record to add to the catalog
3045 * @orig: the system, public or prefix to match
3046 * @replace: the replacement value for the match
3047 *
3048 * Add an entry in the catalog, it may overwrite existing but
3049 * different entries.
Daniel Veillard75b96822001-10-11 18:59:45 +00003050 * If called before any other catalo routine, allows to override the
3051 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003052 *
3053 * Returns 0 if successful, -1 otherwise
3054 */
3055int
3056xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3057 int res = -1;
3058
Daniel Veillard81463942001-10-16 12:34:39 +00003059 if (!xmlCatalogInitialized)
3060 xmlInitializeCatalogData();
3061
3062 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003063 /*
3064 * Specific case where one want to override the default catalog
3065 * put in place by xmlInitializeCatalog();
3066 */
3067 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003068 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003069 xmlDefaultCatalog = xmlNewCatalog(XML_XML_CATALOG_TYPE,
3070 xmlCatalogDefaultPrefer);
3071 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3072 orig, xmlCatalogDefaultPrefer);
3073
Daniel Veillard81463942001-10-16 12:34:39 +00003074 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003075 return(0);
3076 }
3077
Daniel Veillard75b96822001-10-11 18:59:45 +00003078 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003079 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003080 return(res);
3081}
3082
3083/**
3084 * xmlCatalogRemove:
3085 * @value: the value to remove
3086 *
3087 * Remove an entry from the catalog
3088 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003089 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003090 */
3091int
3092xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003093 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003094
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003095 if (!xmlCatalogInitialized)
3096 xmlInitializeCatalog();
3097
Daniel Veillard81463942001-10-16 12:34:39 +00003098 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003099 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003100 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003101 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003102}
3103
3104/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003105 * xmlCatalogConvert:
3106 *
3107 * Convert all the SGML catalog entries as XML ones
3108 *
3109 * Returns the number of entries converted if successful, -1 otherwise
3110 */
3111int
3112xmlCatalogConvert(void) {
3113 int res = -1;
3114
3115 if (!xmlCatalogInitialized)
3116 xmlInitializeCatalog();
3117
Daniel Veillard81463942001-10-16 12:34:39 +00003118 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003119 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003120 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003121 return(res);
3122}
3123
Daniel Veillard75b96822001-10-11 18:59:45 +00003124/************************************************************************
3125 * *
3126 * Public interface manipulating the common preferences *
3127 * *
3128 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003129
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003130/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003131 * xmlCatalogGetDefaults:
3132 *
3133 * Used to get the user preference w.r.t. to what catalogs should
3134 * be accepted
3135 *
3136 * Returns the current xmlCatalogAllow value
3137 */
3138xmlCatalogAllow
3139xmlCatalogGetDefaults(void) {
3140 return(xmlCatalogDefaultAllow);
3141}
3142
3143/**
3144 * xmlCatalogSetDefaults:
3145 *
3146 * Used to set the user preference w.r.t. to what catalogs should
3147 * be accepted
3148 */
3149void
3150xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003151 if (xmlDebugCatalogs) {
3152 switch (allow) {
3153 case XML_CATA_ALLOW_NONE:
3154 xmlGenericError(xmlGenericErrorContext,
3155 "Disabling catalog usage\n");
3156 break;
3157 case XML_CATA_ALLOW_GLOBAL:
3158 xmlGenericError(xmlGenericErrorContext,
3159 "Allowing only global catalogs\n");
3160 break;
3161 case XML_CATA_ALLOW_DOCUMENT:
3162 xmlGenericError(xmlGenericErrorContext,
3163 "Allowing only catalogs from the document\n");
3164 break;
3165 case XML_CATA_ALLOW_ALL:
3166 xmlGenericError(xmlGenericErrorContext,
3167 "Allowing all catalogs\n");
3168 break;
3169 }
3170 }
3171 xmlCatalogDefaultAllow = allow;
3172}
3173
3174/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003175 * xmlCatalogSetDefaultPrefer:
3176 * @prefer: the default preference for delegation
3177 *
3178 * Allows to set the preference between public and system for deletion
3179 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003180 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003181 *
3182 * Returns the previous value of the default preference for delegation
3183 */
3184xmlCatalogPrefer
3185xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3186 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3187
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003188 if (prefer == XML_CATA_PREFER_NONE)
3189 return(ret);
3190
3191 if (xmlDebugCatalogs) {
3192 switch (prefer) {
3193 case XML_CATA_PREFER_PUBLIC:
3194 xmlGenericError(xmlGenericErrorContext,
3195 "Setting catalog preference to PUBLIC\n");
3196 break;
3197 case XML_CATA_PREFER_SYSTEM:
3198 xmlGenericError(xmlGenericErrorContext,
3199 "Setting catalog preference to SYSTEM\n");
3200 break;
3201 case XML_CATA_PREFER_NONE:
3202 break;
3203 }
3204 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003205 xmlCatalogDefaultPrefer = prefer;
3206 return(ret);
3207}
3208
3209/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003210 * xmlCatalogSetDebug:
3211 * @level: the debug level of catalogs required
3212 *
3213 * Used to set the debug level for catalog operation, 0 disable
3214 * debugging, 1 enable it
3215 *
3216 * Returns the previous value of the catalog debugging level
3217 */
3218int
3219xmlCatalogSetDebug(int level) {
3220 int ret = xmlDebugCatalogs;
3221
3222 if (level <= 0)
3223 xmlDebugCatalogs = 0;
3224 else
3225 xmlDebugCatalogs = level;
3226 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003227}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003228
Daniel Veillard75b96822001-10-11 18:59:45 +00003229/************************************************************************
3230 * *
3231 * Minimal interfaces used for per-document catalogs by the parser *
3232 * *
3233 ************************************************************************/
3234
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003235/**
3236 * xmlCatalogFreeLocal:
3237 * @catalogs: a document's list of catalogs
3238 *
3239 * Free up the memory associated to the catalog list
3240 */
3241void
3242xmlCatalogFreeLocal(void *catalogs) {
3243 xmlCatalogEntryPtr catal;
3244
Daniel Veillard81463942001-10-16 12:34:39 +00003245 if (!xmlCatalogInitialized)
3246 xmlInitializeCatalog();
3247
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003248 catal = (xmlCatalogEntryPtr) catalogs;
3249 if (catal != NULL)
3250 xmlFreeCatalogEntryList(catal);
3251}
3252
3253
3254/**
3255 * xmlCatalogAddLocal:
3256 * @catalogs: a document's list of catalogs
3257 * @URL: the URL to a new local catalog
3258 *
3259 * Add the new entry to the catalog list
3260 *
3261 * Returns the updated list
3262 */
3263void *
3264xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3265 xmlCatalogEntryPtr catal, add;
3266
3267 if (!xmlCatalogInitialized)
3268 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003269
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003270 if (URL == NULL)
3271 return(catalogs);
3272
3273 if (xmlDebugCatalogs)
3274 xmlGenericError(xmlGenericErrorContext,
3275 "Adding document catalog %s\n", URL);
3276
3277 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
3278 xmlCatalogDefaultPrefer);
3279 if (add == NULL)
3280 return(catalogs);
3281
3282 catal = (xmlCatalogEntryPtr) catalogs;
3283 if (catal == NULL)
3284 return((void *) add);
3285
3286 while (catal->next != NULL)
3287 catal = catal->next;
3288 catal->next = add;
3289 return(catalogs);
3290}
3291
3292/**
3293 * xmlCatalogLocalResolve:
3294 * @catalogs: a document's list of catalogs
3295 * @pubId: the public ID string
3296 * @sysId: the system ID string
3297 *
3298 * Do a complete resolution lookup of an External Identifier using a
3299 * document's private catalog list
3300 *
3301 * Returns the URI of the resource or NULL if not found, it must be freed
3302 * by the caller.
3303 */
3304xmlChar *
3305xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3306 const xmlChar *sysID) {
3307 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003308 xmlChar *ret;
3309
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003310 if (!xmlCatalogInitialized)
3311 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003312
Daniel Veillard81463942001-10-16 12:34:39 +00003313 if ((pubID == NULL) && (sysID == NULL))
3314 return(NULL);
3315
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003316 if (xmlDebugCatalogs) {
3317 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003318 xmlGenericError(xmlGenericErrorContext,
3319 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003320 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003321 xmlGenericError(xmlGenericErrorContext,
3322 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003323 }
3324 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003325
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003326 catal = (xmlCatalogEntryPtr) catalogs;
3327 if (catal == NULL)
3328 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003329 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3330 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3331 return(ret);
3332 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003333}
3334
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003335/**
3336 * xmlCatalogLocalResolveURI:
3337 * @catalogs: a document's list of catalogs
3338 * @pubId: the URI
3339 *
3340 * Do a complete resolution lookup of an URI using a
3341 * document's private catalog list
3342 *
3343 * Returns the URI of the resource or NULL if not found, it must be freed
3344 * by the caller.
3345 */
3346xmlChar *
3347xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3348 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003349 xmlChar *ret;
3350
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003351 if (!xmlCatalogInitialized)
3352 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003353
Daniel Veillard81463942001-10-16 12:34:39 +00003354 if (URI == NULL)
3355 return(NULL);
3356
Daniel Veillard6990bf32001-08-23 21:17:48 +00003357 if (xmlDebugCatalogs)
3358 xmlGenericError(xmlGenericErrorContext,
3359 "Resolve URI %s\n", URI);
3360
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003361 catal = (xmlCatalogEntryPtr) catalogs;
3362 if (catal == NULL)
3363 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003364 ret = xmlCatalogListXMLResolveURI(catal, URI);
3365 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3366 return(ret);
3367 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003368}
3369
Daniel Veillard75b96822001-10-11 18:59:45 +00003370/************************************************************************
3371 * *
3372 * Deprecated interfaces *
3373 * *
3374 ************************************************************************/
3375/**
3376 * xmlCatalogGetSystem:
3377 * @pubId: the public ID string
3378 *
3379 * Try to lookup the system ID associated to a public ID
3380 * DEPRECATED, use xmlCatalogResolveSystem()
3381 *
3382 * Returns the system ID if found or NULL otherwise.
3383 */
3384const xmlChar *
3385xmlCatalogGetSystem(const xmlChar *sysID) {
3386 xmlChar *ret;
3387 static xmlChar result[1000];
3388 static int msg = 0;
3389
Daniel Veillard81463942001-10-16 12:34:39 +00003390 if (!xmlCatalogInitialized)
3391 xmlInitializeCatalog();
3392
Daniel Veillard75b96822001-10-11 18:59:45 +00003393 if (msg == 0) {
3394 xmlGenericError(xmlGenericErrorContext,
3395 "Use of deprecated xmlCatalogGetSystem() call\n");
3396 msg++;
3397 }
3398
3399 if (sysID == NULL)
3400 return(NULL);
3401
Daniel Veillard75b96822001-10-11 18:59:45 +00003402 /*
3403 * Check first the XML catalogs
3404 */
3405 if (xmlDefaultCatalog != NULL) {
3406 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3407 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3408 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3409 result[sizeof(result) - 1] = 0;
3410 return(result);
3411 }
3412 }
3413
3414 if (xmlDefaultCatalog != NULL)
3415 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3416 return(NULL);
3417}
3418
3419/**
3420 * xmlCatalogGetPublic:
3421 * @pubId: the public ID string
3422 *
3423 * Try to lookup the system ID associated to a public ID
3424 * DEPRECATED, use xmlCatalogResolvePublic()
3425 *
3426 * Returns the system ID if found or NULL otherwise.
3427 */
3428const xmlChar *
3429xmlCatalogGetPublic(const xmlChar *pubID) {
3430 xmlChar *ret;
3431 static xmlChar result[1000];
3432 static int msg = 0;
3433
Daniel Veillard81463942001-10-16 12:34:39 +00003434 if (!xmlCatalogInitialized)
3435 xmlInitializeCatalog();
3436
Daniel Veillard75b96822001-10-11 18:59:45 +00003437 if (msg == 0) {
3438 xmlGenericError(xmlGenericErrorContext,
3439 "Use of deprecated xmlCatalogGetPublic() call\n");
3440 msg++;
3441 }
3442
3443 if (pubID == NULL)
3444 return(NULL);
3445
Daniel Veillard75b96822001-10-11 18:59:45 +00003446 /*
3447 * Check first the XML catalogs
3448 */
3449 if (xmlDefaultCatalog != NULL) {
3450 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3451 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3452 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3453 result[sizeof(result) - 1] = 0;
3454 return(result);
3455 }
3456 }
3457
3458 if (xmlDefaultCatalog != NULL)
3459 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3460 return(NULL);
3461}
3462
Daniel Veillarda7374592001-05-10 14:17:55 +00003463#endif /* LIBXML_CATALOG_ENABLED */