blob: 1b7bd8dafa20bd81b6eb90c590d7193a3dc1bf27 [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>
40
Daniel Veillard6990bf32001-08-23 21:17:48 +000041#define MAX_DELEGATE 50
42
Daniel Veillard344cee72001-08-20 00:08:40 +000043/**
44 * TODO:
45 *
46 * macro to flag unimplemented blocks
47 */
48#define TODO \
49 xmlGenericError(xmlGenericErrorContext, \
50 "Unimplemented block at %s:%d\n", \
51 __FILE__, __LINE__);
52
Daniel Veillardcda96922001-08-21 10:56:31 +000053#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000054#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000055#ifndef XML_XML_DEFAULT_CATALOG
56#define XML_XML_DEFAULT_CATALOG "/etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000057#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000058#ifndef XML_SGML_DEFAULT_CATALOG
59#define XML_SGML_DEFAULT_CATALOG "/etc/sgml/catalog"
60#endif
61
62int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000063
Daniel Veillarda7374592001-05-10 14:17:55 +000064/************************************************************************
65 * *
66 * Types, all private *
67 * *
68 ************************************************************************/
69
70typedef enum {
71 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000072 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000073 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000074 XML_CATA_NEXT_CATALOG,
75 XML_CATA_PUBLIC,
76 XML_CATA_SYSTEM,
77 XML_CATA_REWRITE_SYSTEM,
78 XML_CATA_DELEGATE_PUBLIC,
79 XML_CATA_DELEGATE_SYSTEM,
80 XML_CATA_URI,
81 XML_CATA_REWRITE_URI,
82 XML_CATA_DELEGATE_URI,
83 SGML_CATA_SYSTEM,
84 SGML_CATA_PUBLIC,
85 SGML_CATA_ENTITY,
86 SGML_CATA_PENTITY,
87 SGML_CATA_DOCTYPE,
88 SGML_CATA_LINKTYPE,
89 SGML_CATA_NOTATION,
90 SGML_CATA_DELEGATE,
91 SGML_CATA_BASE,
92 SGML_CATA_CATALOG,
93 SGML_CATA_DOCUMENT,
94 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000095} xmlCatalogEntryType;
96
97typedef struct _xmlCatalogEntry xmlCatalogEntry;
98typedef xmlCatalogEntry *xmlCatalogEntryPtr;
99struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000100 struct _xmlCatalogEntry *next;
101 struct _xmlCatalogEntry *parent;
102 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000103 xmlCatalogEntryType type;
104 xmlChar *name;
105 xmlChar *value;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000106 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000107 int dealloc;
Daniel Veillarda7374592001-05-10 14:17:55 +0000108};
109
Daniel Veillard75b96822001-10-11 18:59:45 +0000110typedef enum {
111 XML_XML_CATALOG_TYPE = 1,
112 XML_SGML_CATALOG_TYPE
113} xmlCatalogType;
114
115#define XML_MAX_SGML_CATA_DEPTH 10
116struct _xmlCatalog {
117 xmlCatalogType type; /* either XML or SGML */
118
119 /*
120 * SGML Catalogs are stored as a simple hash table of catalog entries
121 * Catalog stack to check against overflows when building the
122 * SGML catalog
123 */
124 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
125 int catalNr; /* Number of current catal streams */
126 int catalMax; /* Max number of catal streams */
127 xmlHashTablePtr sgml;
128
129 /*
130 * XML Catalogs are stored as a tree of Catalog entries
131 */
132 xmlCatalogPrefer prefer;
133 xmlCatalogEntryPtr xml;
134};
135
136/************************************************************************
137 * *
138 * Global variables *
139 * *
140 ************************************************************************/
141
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000142static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000143static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000144
145/*
146 * Hash table containing all the trees of XML catalogs parsed by
147 * the application.
148 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000149static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000150
151/*
152 * The default catalog in use by the application
153 */
154static xmlCatalogPtr xmlDefaultCatalog = NULL;
155
156/*
157 * Whether the catalog support was initialized.
158 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000159static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000160
Daniel Veillarda7374592001-05-10 14:17:55 +0000161
Daniel Veillard344cee72001-08-20 00:08:40 +0000162static int xmlDebugCatalogs = 0; /* used for debugging */
163
Daniel Veillarda7374592001-05-10 14:17:55 +0000164/************************************************************************
165 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000166 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000167 * *
168 ************************************************************************/
169
Daniel Veillard75b96822001-10-11 18:59:45 +0000170/**
171 * xmlNewCatalogEntry:
172 * @type: type of entry
173 * @name: name of the entry
174 * @value: value of the entry
175 * @prefer: the PUBLIC vs. SYSTEM current preference value
176 *
177 * create a new Catalog entry, this type is shared both by XML and
178 * SGML catalogs, but the acceptable types values differs.
179 *
180 * Returns the xmlCatalogEntryPtr or NULL in case of error
181 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000182static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000183xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000184 const xmlChar *value, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000185 xmlCatalogEntryPtr ret;
186
187 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
188 if (ret == NULL) {
189 xmlGenericError(xmlGenericErrorContext,
190 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
191 return(NULL);
192 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000193 ret->next = NULL;
194 ret->parent = NULL;
195 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000196 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000197 if (name != NULL)
198 ret->name = xmlStrdup(name);
199 else
200 ret->name = NULL;
201 if (value != NULL)
202 ret->value = xmlStrdup(value);
203 else
204 ret->value = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000205 ret->prefer = prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000206 ret->dealloc = 1;
Daniel Veillarda7374592001-05-10 14:17:55 +0000207 return(ret);
208}
209
210static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000211xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
212
Daniel Veillard75b96822001-10-11 18:59:45 +0000213/**
214 * xmlFreeCatalogEntry:
215 * @ret: a Catalog entry
216 *
217 * Free the memory allocated to a Catalog entry
218 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000219static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000220xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
221 if (ret == NULL)
222 return;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000223 if ((ret->children != NULL) && (ret->dealloc == 1))
Daniel Veillard344cee72001-08-20 00:08:40 +0000224 xmlFreeCatalogEntryList(ret->children);
Daniel Veillarda7374592001-05-10 14:17:55 +0000225 if (ret->name != NULL)
226 xmlFree(ret->name);
227 if (ret->value != NULL)
228 xmlFree(ret->value);
229 xmlFree(ret);
230}
231
Daniel Veillard75b96822001-10-11 18:59:45 +0000232/**
233 * xmlFreeCatalogEntryList:
234 * @ret: a Catalog entry list
235 *
236 * Free the memory allocated to a full chained list of Catalog entries
237 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000238static void
239xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
240 xmlCatalogEntryPtr next;
241
242 while (ret != NULL) {
243 next = ret->next;
244 xmlFreeCatalogEntry(ret);
245 ret = next;
246 }
247}
248
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000249/**
Daniel Veillard75b96822001-10-11 18:59:45 +0000250 * xmlNewCatalog:
251 * @type: type of catalog
252 * @prefer: the PUBLIC vs. SYSTEM current preference value
253 *
254 * create a new Catalog, this type is shared both by XML and
255 * SGML catalogs, but the acceptable types values differs.
256 *
257 * Returns the xmlCatalogPtr or NULL in case of error
258 */
259static xmlCatalogPtr
260xmlNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
261 xmlCatalogPtr ret;
262
263 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
264 if (ret == NULL) {
265 xmlGenericError(xmlGenericErrorContext,
266 "malloc of %d byte failed\n", sizeof(xmlCatalog));
267 return(NULL);
268 }
269 memset(ret, 0, sizeof(xmlCatalog));
270 ret->type = type;
271 ret->catalNr = 0;
272 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
273 ret->prefer = prefer;
274 return(ret);
275}
276
277/**
278 * xmlFreeCatalog:
279 * @catal: a Catalog entry
280 *
281 * Free the memory allocated to a Catalog
282 */
283void
284xmlFreeCatalog(xmlCatalogPtr catal) {
285 if (catal == NULL)
286 return;
287 if (catal->xml != NULL)
288 xmlFreeCatalogEntryList(catal->xml);
289 if (catal->sgml != NULL)
290 xmlHashFree(catal->sgml,
291 (xmlHashDeallocator) xmlFreeCatalogEntry);
292 xmlFree(catal);
293}
294
295/************************************************************************
296 * *
297 * Serializing Catalogs *
298 * *
299 ************************************************************************/
300
301/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000302 * xmlCatalogDumpEntry:
303 * @entry: the
304 * @out: the file.
305 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000306 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000307 */
308static void
309xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
310 if ((entry == NULL) || (out == NULL))
311 return;
312 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000313 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000314 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000315 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000316 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000317 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000318 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000319 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000320 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000321 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000322 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000323 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000324 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000325 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000326 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000327 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000328 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000329 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000330 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000331 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000332 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000333 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000334 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000335 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000336 fprintf(out, "SGMLDECL "); break;
337 default:
338 return;
339 }
340 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000341 case SGML_CATA_ENTITY:
342 case SGML_CATA_PENTITY:
343 case SGML_CATA_DOCTYPE:
344 case SGML_CATA_LINKTYPE:
345 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000346 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000347 case SGML_CATA_PUBLIC:
348 case SGML_CATA_SYSTEM:
349 case SGML_CATA_SGMLDECL:
350 case SGML_CATA_DOCUMENT:
351 case SGML_CATA_CATALOG:
352 case SGML_CATA_BASE:
353 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000354 fprintf(out, "\"%s\"", entry->name); break;
355 default:
356 break;
357 }
358 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000359 case SGML_CATA_ENTITY:
360 case SGML_CATA_PENTITY:
361 case SGML_CATA_DOCTYPE:
362 case SGML_CATA_LINKTYPE:
363 case SGML_CATA_NOTATION:
364 case SGML_CATA_PUBLIC:
365 case SGML_CATA_SYSTEM:
366 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000367 fprintf(out, " \"%s\"", entry->value); break;
368 default:
369 break;
370 }
371 fprintf(out, "\n");
372}
373
Daniel Veillard75b96822001-10-11 18:59:45 +0000374static int
375xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
376 int ret;
377 xmlDocPtr doc;
378 xmlNsPtr ns;
379 xmlDtdPtr dtd;
380 xmlNodePtr node, catalog;
381 xmlOutputBufferPtr buf;
382 xmlCatalogEntryPtr cur;
383
384 /*
385 * Rebuild a catalog
386 */
387 doc = xmlNewDoc(NULL);
388 if (doc == NULL)
389 return(-1);
390 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
391 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
392BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
393
394 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
395
396 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
397 if (ns == NULL) {
398 xmlFreeDoc(doc);
399 return(-1);
400 }
401 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
402 if (catalog == NULL) {
403 xmlFreeNs(ns);
404 xmlFreeDoc(doc);
405 return(-1);
406 }
407 catalog->nsDef = ns;
408 xmlAddChild((xmlNodePtr) doc, catalog);
409
410 /*
411 * add all the catalog entries
412 */
413 cur = catal;
414 while (cur != NULL) {
415 switch (cur->type) {
416 case XML_CATA_BROKEN_CATALOG:
417 case XML_CATA_CATALOG:
418 if (cur == catal) {
419 cur = cur->children;
420 continue;
421 }
422 break;
423 case XML_CATA_NEXT_CATALOG:
424 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
425 xmlSetProp(node, BAD_CAST "catalog", cur->value);
426 xmlAddChild(catalog, node);
427 break;
428 case XML_CATA_NONE:
429 break;
430 case XML_CATA_PUBLIC:
431 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
432 xmlSetProp(node, BAD_CAST "publicId", cur->name);
433 xmlSetProp(node, BAD_CAST "uri", cur->value);
434 xmlAddChild(catalog, node);
435 break;
436 case XML_CATA_SYSTEM:
437 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
438 xmlSetProp(node, BAD_CAST "systemId", cur->name);
439 xmlSetProp(node, BAD_CAST "uri", cur->value);
440 xmlAddChild(catalog, node);
441 break;
442 case XML_CATA_REWRITE_SYSTEM:
443 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
444 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
445 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
446 xmlAddChild(catalog, node);
447 break;
448 case XML_CATA_DELEGATE_PUBLIC:
449 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
450 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
451 xmlSetProp(node, BAD_CAST "catalog", cur->value);
452 xmlAddChild(catalog, node);
453 break;
454 case XML_CATA_DELEGATE_SYSTEM:
455 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
456 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
457 xmlSetProp(node, BAD_CAST "catalog", cur->value);
458 xmlAddChild(catalog, node);
459 break;
460 case XML_CATA_URI:
461 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
462 xmlSetProp(node, BAD_CAST "name", cur->name);
463 xmlSetProp(node, BAD_CAST "uri", cur->value);
464 xmlAddChild(catalog, node);
465 break;
466 case XML_CATA_REWRITE_URI:
467 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
468 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
469 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
470 xmlAddChild(catalog, node);
471 break;
472 case XML_CATA_DELEGATE_URI:
473 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
474 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
475 xmlSetProp(node, BAD_CAST "catalog", cur->value);
476 xmlAddChild(catalog, node);
477 break;
478 case SGML_CATA_SYSTEM:
479 case SGML_CATA_PUBLIC:
480 case SGML_CATA_ENTITY:
481 case SGML_CATA_PENTITY:
482 case SGML_CATA_DOCTYPE:
483 case SGML_CATA_LINKTYPE:
484 case SGML_CATA_NOTATION:
485 case SGML_CATA_DELEGATE:
486 case SGML_CATA_BASE:
487 case SGML_CATA_CATALOG:
488 case SGML_CATA_DOCUMENT:
489 case SGML_CATA_SGMLDECL:
490 break;
491 }
492 cur = cur->next;
493 }
494
495 /*
496 * reserialize it
497 */
498 buf = xmlOutputBufferCreateFile(out, NULL);
499 if (buf == NULL) {
500 xmlFreeDoc(doc);
501 return(-1);
502 }
503 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
504
505 /*
506 * Free it
507 */
508 xmlFreeDoc(doc);
509
510 return(ret);
511}
512
513/************************************************************************
514 * *
515 * Converting SGML Catalogs to XML *
516 * *
517 ************************************************************************/
518
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000519/**
520 * xmlCatalogConvertEntry:
521 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000522 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000523 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000524 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000525 */
526static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000527xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
528 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
529 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000530 return;
531 switch (entry->type) {
532 case SGML_CATA_ENTITY:
533 entry->type = XML_CATA_PUBLIC;
534 break;
535 case SGML_CATA_PENTITY:
536 entry->type = XML_CATA_PUBLIC;
537 break;
538 case SGML_CATA_DOCTYPE:
539 entry->type = XML_CATA_PUBLIC;
540 break;
541 case SGML_CATA_LINKTYPE:
542 entry->type = XML_CATA_PUBLIC;
543 break;
544 case SGML_CATA_NOTATION:
545 entry->type = XML_CATA_PUBLIC;
546 break;
547 case SGML_CATA_PUBLIC:
548 entry->type = XML_CATA_PUBLIC;
549 break;
550 case SGML_CATA_SYSTEM:
551 entry->type = XML_CATA_SYSTEM;
552 break;
553 case SGML_CATA_DELEGATE:
554 entry->type = XML_CATA_DELEGATE_PUBLIC;
555 break;
556 case SGML_CATA_CATALOG:
557 entry->type = XML_CATA_CATALOG;
558 break;
559 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000560 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000561 (xmlHashDeallocator) xmlFreeCatalogEntry);
562 return;
563 }
564 /*
565 * Conversion successful, remove from the SGML catalog
566 * and add it to the default XML one
567 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000568 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
569 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000570 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000571 if (catal->xml->children == NULL)
572 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000573 else {
574 xmlCatalogEntryPtr prev;
575
Daniel Veillard75b96822001-10-11 18:59:45 +0000576 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000577 while (prev->next != NULL)
578 prev = prev->next;
579 prev->next = entry;
580 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000581}
582
583/**
584 * xmlConvertSGMLCatalog:
585 * @catal: the catalog
586 *
587 * Convert all the SGML catalog entries as XML ones
588 *
589 * Returns the number of entries converted if successful, -1 otherwise
590 */
591int
592xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
593
594 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
595 return(-1);
596
597 if (xmlDebugCatalogs) {
598 xmlGenericError(xmlGenericErrorContext,
599 "Converting SGML catalog to XML\n");
600 }
601 xmlHashScan(catal->sgml,
602 (xmlHashScanner) xmlCatalogConvertEntry,
603 &catal);
604 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000605}
606
Daniel Veillarda7374592001-05-10 14:17:55 +0000607/************************************************************************
608 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000609 * Helper function *
610 * *
611 ************************************************************************/
612
613/**
614 * xmlCatalogUnWrapURN:
615 * @urn: an "urn:publicid:" to unwrapp
616 *
617 * Expand the URN into the equivalent Public Identifier
618 *
619 * Returns the new identifier or NULL, the string must be deallocated
620 * by the caller.
621 */
622static xmlChar *
623xmlCatalogUnWrapURN(const xmlChar *urn) {
624 xmlChar result[2000];
625 unsigned int i = 0;
626
627 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
628 return(NULL);
629 urn += sizeof(XML_URN_PUBID) - 1;
630
631 while (*urn != 0) {
632 if (i > sizeof(result) - 3)
633 break;
634 if (*urn == '+') {
635 result[i++] = ' ';
636 urn++;
637 } else if (*urn == ':') {
638 result[i++] = '/';
639 result[i++] = '/';
640 urn++;
641 } else if (*urn == ';') {
642 result[i++] = ':';
643 result[i++] = ':';
644 urn++;
645 } else if (*urn == '%') {
646 if ((urn[1] == '2') && (urn[1] == 'B'))
647 result[i++] = '+';
648 else if ((urn[1] == '3') && (urn[1] == 'A'))
649 result[i++] = ':';
650 else if ((urn[1] == '2') && (urn[1] == 'F'))
651 result[i++] = '/';
652 else if ((urn[1] == '3') && (urn[1] == 'B'))
653 result[i++] = ';';
654 else if ((urn[1] == '2') && (urn[1] == '7'))
655 result[i++] = '\'';
656 else if ((urn[1] == '3') && (urn[1] == 'F'))
657 result[i++] = '?';
658 else if ((urn[1] == '2') && (urn[1] == '3'))
659 result[i++] = '#';
660 else if ((urn[1] == '2') && (urn[1] == '5'))
661 result[i++] = '%';
662 else {
663 result[i++] = *urn;
664 urn++;
665 continue;
666 }
667 urn += 3;
668 } else {
669 result[i++] = *urn;
670 urn++;
671 }
672 }
673 result[i] = 0;
674
675 return(xmlStrdup(result));
676}
677
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000678/**
679 * xmlParseCatalogFile:
680 * @filename: the filename
681 *
682 * parse an XML file and build a tree. It's like xmlParseFile()
683 * except it bypass all catalog lookups.
684 *
685 * Returns the resulting document tree or NULL in case of error
686 */
687
688xmlDocPtr
689xmlParseCatalogFile(const char *filename) {
690 xmlDocPtr ret;
691 xmlParserCtxtPtr ctxt;
692 char *directory = NULL;
693 xmlParserInputPtr inputStream;
694 xmlParserInputBufferPtr buf;
695
696 ctxt = xmlNewParserCtxt();
697 if (ctxt == NULL) {
698 if (xmlDefaultSAXHandler.error != NULL) {
699 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
700 }
701 return(NULL);
702 }
703
704 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
705 if (buf == NULL) {
706 xmlFreeParserCtxt(ctxt);
707 return(NULL);
708 }
709
710 inputStream = xmlNewInputStream(ctxt);
711 if (inputStream == NULL) {
712 xmlFreeParserCtxt(ctxt);
713 return(NULL);
714 }
715
716 inputStream->filename = xmlMemStrdup(filename);
717 inputStream->buf = buf;
718 inputStream->base = inputStream->buf->buffer->content;
719 inputStream->cur = inputStream->buf->buffer->content;
720 inputStream->end =
721 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
722
723 inputPush(ctxt, inputStream);
724 if ((ctxt->directory == NULL) && (directory == NULL))
725 directory = xmlParserGetDirectory(filename);
726 if ((ctxt->directory == NULL) && (directory != NULL))
727 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000728 ctxt->valid = 0;
729 ctxt->validate = 0;
730 ctxt->loadsubset = 0;
731 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000732
733 xmlParseDocument(ctxt);
734
735 if (ctxt->wellFormed)
736 ret = ctxt->myDoc;
737 else {
738 ret = NULL;
739 xmlFreeDoc(ctxt->myDoc);
740 ctxt->myDoc = NULL;
741 }
742 xmlFreeParserCtxt(ctxt);
743
744 return(ret);
745}
746
Daniel Veillard75b96822001-10-11 18:59:45 +0000747/**
748 * xmlLoadFileContent:
749 * @filename: a file path
750 *
751 * Load a file content into memory.
752 *
753 * Returns a pointer to the 0 terminated string or NULL in case of error
754 */
755static xmlChar *
756xmlLoadFileContent(const char *filename)
757{
758#ifdef HAVE_STAT
759 int fd;
760#else
761 FILE *fd;
762#endif
763 int len;
764 long size;
765
766#ifdef HAVE_STAT
767 struct stat info;
768#endif
769 xmlChar *content;
770
771 if (filename == NULL)
772 return (NULL);
773
774#ifdef HAVE_STAT
775 if (stat(filename, &info) < 0)
776 return (NULL);
777#endif
778
779#ifdef HAVE_STAT
780 if ((fd = open(filename, O_RDONLY)) < 0) {
781#else
782 if ((fd = fopen(filename, "rb")) == NULL) {
783#endif
784 return (NULL);
785 }
786#ifdef HAVE_STAT
787 size = info.st_size;
788#else
789 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
790 fclose(fd);
791 return (NULL);
792 }
793#endif
794 content = xmlMalloc(size + 10);
795 if (content == NULL) {
796 xmlGenericError(xmlGenericErrorContext,
797 "malloc of %d byte failed\n", size + 10);
798 return (NULL);
799 }
800#ifdef HAVE_STAT
801 len = read(fd, content, size);
802#else
803 len = fread(content, 1, size, fd);
804#endif
805 if (len < 0) {
806 xmlFree(content);
807 return (NULL);
808 }
809#ifdef HAVE_STAT
810 close(fd);
811#else
812 fclose(fd);
813#endif
814 content[len] = 0;
815
816 return(content);
817}
818
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000819/************************************************************************
820 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000821 * The XML Catalog parser *
822 * *
823 ************************************************************************/
824
825static xmlCatalogEntryPtr
826xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000827static xmlCatalogEntryPtr
828xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
829 const char *file);
830static void
831xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
832 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000833static xmlChar *
834xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
835 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000836static xmlChar *
837xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
838
Daniel Veillard344cee72001-08-20 00:08:40 +0000839
Daniel Veillard75b96822001-10-11 18:59:45 +0000840/**
841 * xmlGetXMLCatalogEntryType:
842 * @name: the name
843 *
844 * lookup the internal type associated to an XML catalog entry name
845 *
846 * Returns the type associate with that name
847 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000848static xmlCatalogEntryType
849xmlGetXMLCatalogEntryType(const xmlChar *name) {
850 xmlCatalogEntryType type = XML_CATA_NONE;
851 if (xmlStrEqual(name, (const xmlChar *) "system"))
852 type = XML_CATA_SYSTEM;
853 else if (xmlStrEqual(name, (const xmlChar *) "public"))
854 type = XML_CATA_PUBLIC;
855 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
856 type = XML_CATA_REWRITE_SYSTEM;
857 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
858 type = XML_CATA_DELEGATE_PUBLIC;
859 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
860 type = XML_CATA_DELEGATE_SYSTEM;
861 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
862 type = XML_CATA_URI;
863 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
864 type = XML_CATA_REWRITE_URI;
865 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
866 type = XML_CATA_DELEGATE_URI;
867 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
868 type = XML_CATA_NEXT_CATALOG;
869 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
870 type = XML_CATA_CATALOG;
871 return(type);
872}
873
Daniel Veillard75b96822001-10-11 18:59:45 +0000874/**
875 * xmlParseXMLCatalogOneNode:
876 * @cur: the XML node
877 * @type: the type of Catalog entry
878 * @name: the name of the node
879 * @attrName: the attribute holding the value
880 * @uriAttrName: the attribute holding the URI-Reference
881 * @prefer: the PUBLIC vs. SYSTEM current preference value
882 *
883 * Finishes the examination of an XML tree node of a catalog and build
884 * a Catalog entry from it.
885 *
886 * Returns the new Catalog entry node or NULL in case of error.
887 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000888static xmlCatalogEntryPtr
889xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
890 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000891 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000892 int ok = 1;
893 xmlChar *uriValue;
894 xmlChar *nameValue = NULL;
895 xmlChar *base = NULL;
896 xmlChar *URL = NULL;
897 xmlCatalogEntryPtr ret = NULL;
898
899 if (attrName != NULL) {
900 nameValue = xmlGetProp(cur, attrName);
901 if (nameValue == NULL) {
902 xmlGenericError(xmlGenericErrorContext,
903 "%s entry lacks '%s'\n", name, attrName);
904 ok = 0;
905 }
906 }
907 uriValue = xmlGetProp(cur, uriAttrName);
908 if (uriValue == NULL) {
909 xmlGenericError(xmlGenericErrorContext,
910 "%s entry lacks '%s'\n", name, uriAttrName);
911 ok = 0;
912 }
913 if (!ok) {
914 if (nameValue != NULL)
915 xmlFree(nameValue);
916 if (uriValue != NULL)
917 xmlFree(uriValue);
918 return(NULL);
919 }
920
921 base = xmlNodeGetBase(cur->doc, cur);
922 URL = xmlBuildURI(uriValue, base);
923 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000924 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000925 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000926 xmlGenericError(xmlGenericErrorContext,
927 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000928 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000929 xmlGenericError(xmlGenericErrorContext,
930 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000931 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000932 ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000933 } else {
934 xmlGenericError(xmlGenericErrorContext,
935 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
936 }
937 if (nameValue != NULL)
938 xmlFree(nameValue);
939 if (uriValue != NULL)
940 xmlFree(uriValue);
941 if (base != NULL)
942 xmlFree(base);
943 if (URL != NULL)
944 xmlFree(URL);
945 return(ret);
946}
947
Daniel Veillard75b96822001-10-11 18:59:45 +0000948/**
949 * xmlParseXMLCatalogNode:
950 * @cur: the XML node
951 * @prefer: the PUBLIC vs. SYSTEM current preference value
952 * @parent: the parent Catalog entry
953 *
954 * Examines an XML tree node of a catalog and build
955 * a Catalog entry from it adding it to its parent. The examination can
956 * be recursive.
957 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000958static void
959xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
960 xmlCatalogEntryPtr parent)
961{
962 xmlChar *uri = NULL;
963 xmlChar *URL = NULL;
964 xmlChar *base = NULL;
965 xmlCatalogEntryPtr entry = NULL;
966
967 if (cur == NULL)
968 return;
969 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
970 xmlChar *prop;
971
972 prop = xmlGetProp(cur, BAD_CAST "prefer");
973 if (prop != NULL) {
974 if (xmlStrEqual(prop, BAD_CAST "system")) {
975 prefer = XML_CATA_PREFER_SYSTEM;
976 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
977 prefer = XML_CATA_PREFER_PUBLIC;
978 } else {
979 xmlGenericError(xmlGenericErrorContext,
980 "Invalid value for prefer: '%s'\n", prop);
981 }
982 xmlFree(prop);
983 }
984 /*
985 * Recurse to propagate prefer to the subtree
986 * (xml:base handling is automated)
987 */
988 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
989 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
990 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000991 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000992 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
993 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000994 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000995 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
996 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
997 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000998 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000999 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1000 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1001 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001002 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001003 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1004 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1005 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001006 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001007 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1008 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1009 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001010 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001011 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1012 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1013 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001014 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001015 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1016 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1017 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001018 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001019 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1020 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1021 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001022 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001023 }
1024 if ((entry != NULL) && (parent != NULL)) {
1025 entry->parent = parent;
1026 if (parent->children == NULL)
1027 parent->children = entry;
1028 else {
1029 xmlCatalogEntryPtr prev;
1030
1031 prev = parent->children;
1032 while (prev->next != NULL)
1033 prev = prev->next;
1034 prev->next = entry;
1035 }
1036 }
1037 if (base != NULL)
1038 xmlFree(base);
1039 if (uri != NULL)
1040 xmlFree(uri);
1041 if (URL != NULL)
1042 xmlFree(URL);
1043}
1044
Daniel Veillard75b96822001-10-11 18:59:45 +00001045/**
1046 * xmlParseXMLCatalogNodeList:
1047 * @cur: the XML node list of siblings
1048 * @prefer: the PUBLIC vs. SYSTEM current preference value
1049 * @parent: the parent Catalog entry
1050 *
1051 * Examines a list of XML sibling nodes of a catalog and build
1052 * a list of Catalog entry from it adding it to the parent.
1053 * The examination will recurse to examine node subtrees.
1054 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001055static void
1056xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1057 xmlCatalogEntryPtr parent) {
1058 while (cur != NULL) {
1059 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1060 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1061 xmlParseXMLCatalogNode(cur, prefer, parent);
1062 }
1063 cur = cur->next;
1064 }
1065 /* TODO: sort the list according to REWRITE lengths and prefer value */
1066}
1067
Daniel Veillard75b96822001-10-11 18:59:45 +00001068/**
1069 * xmlParseXMLCatalog:
1070 * @value: the content in-memory of the catalog serialization
1071 * @prefer: the PUBLIC vs. SYSTEM current preference value
1072 * @file: the filename for the catalog
1073 *
1074 * Parses the catalog content to extract the XML tree and then analyze the
1075 * tree to build a list of Catalog entries corresponding to this catalog
1076 *
1077 * Returns the resulting Catalog entries list
1078 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001079static xmlCatalogEntryPtr
1080xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
1081 const char *file) {
1082 xmlDocPtr doc;
1083 xmlNodePtr cur;
1084 xmlChar *prop;
1085 xmlCatalogEntryPtr parent = NULL;
1086
1087 if ((value == NULL) || (file == NULL))
1088 return(NULL);
1089
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001090 if (xmlDebugCatalogs)
1091 xmlGenericError(xmlGenericErrorContext,
1092 "Parsing catalog %s's content\n", file);
1093
Daniel Veillard344cee72001-08-20 00:08:40 +00001094 doc = xmlParseDoc((xmlChar *) value);
1095 if (doc == NULL)
1096 return(NULL);
1097 doc->URL = xmlStrdup((const xmlChar *) file);
1098
1099 cur = xmlDocGetRootElement(doc);
1100 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1101 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1102 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1103
Daniel Veillard344cee72001-08-20 00:08:40 +00001104 prop = xmlGetProp(cur, BAD_CAST "prefer");
1105 if (prop != NULL) {
1106 if (xmlStrEqual(prop, BAD_CAST "system")) {
1107 prefer = XML_CATA_PREFER_SYSTEM;
1108 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1109 prefer = XML_CATA_PREFER_PUBLIC;
1110 } else {
1111 xmlGenericError(xmlGenericErrorContext,
1112 "Invalid value for prefer: '%s'\n",
1113 prop);
1114 }
1115 xmlFree(prop);
1116 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001117 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1118 (const xmlChar *)file, prefer);
1119 if (parent == NULL) {
1120 xmlFreeDoc(doc);
1121 return(NULL);
1122 }
1123
Daniel Veillard344cee72001-08-20 00:08:40 +00001124 cur = cur->children;
1125 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1126 } else {
1127 xmlGenericError(xmlGenericErrorContext,
1128 "File %s is not an XML Catalog\n", file);
1129 xmlFreeDoc(doc);
1130 return(NULL);
1131 }
1132 xmlFreeDoc(doc);
1133 return(parent);
1134}
1135
Daniel Veillard75b96822001-10-11 18:59:45 +00001136/**
1137 * xmlParseXMLCatalogFile:
1138 * @prefer: the PUBLIC vs. SYSTEM current preference value
1139 * @filename: the filename for the catalog
1140 *
1141 * Parses the catalog file to extract the XML tree and then analyze the
1142 * tree to build a list of Catalog entries corresponding to this catalog
1143 *
1144 * Returns the resulting Catalog entries list
1145 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001146static xmlCatalogEntryPtr
1147xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1148 xmlDocPtr doc;
1149 xmlNodePtr cur;
1150 xmlChar *prop;
1151 xmlCatalogEntryPtr parent = NULL;
1152
1153 if (filename == NULL)
1154 return(NULL);
1155
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001156 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001157 if (doc == NULL) {
1158 if (xmlDebugCatalogs)
1159 xmlGenericError(xmlGenericErrorContext,
1160 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001161 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001162 }
1163
1164 if (xmlDebugCatalogs)
1165 xmlGenericError(xmlGenericErrorContext,
1166 "Parsing catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001167
1168 cur = xmlDocGetRootElement(doc);
1169 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1170 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1171 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1172
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001173 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1174 (const xmlChar *)filename, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001175 if (parent == NULL) {
1176 xmlFreeDoc(doc);
1177 return(NULL);
1178 }
1179
1180 prop = xmlGetProp(cur, BAD_CAST "prefer");
1181 if (prop != NULL) {
1182 if (xmlStrEqual(prop, BAD_CAST "system")) {
1183 prefer = XML_CATA_PREFER_SYSTEM;
1184 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1185 prefer = XML_CATA_PREFER_PUBLIC;
1186 } else {
1187 xmlGenericError(xmlGenericErrorContext,
1188 "Invalid value for prefer: '%s'\n",
1189 prop);
1190 }
1191 xmlFree(prop);
1192 }
1193 cur = cur->children;
1194 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1195 } else {
1196 xmlGenericError(xmlGenericErrorContext,
1197 "File %s is not an XML Catalog\n", filename);
1198 xmlFreeDoc(doc);
1199 return(NULL);
1200 }
1201 xmlFreeDoc(doc);
1202 return(parent);
1203}
1204
Daniel Veillardcda96922001-08-21 10:56:31 +00001205/**
1206 * xmlFetchXMLCatalogFile:
1207 * @catal: an existing but incomplete catalog entry
1208 *
1209 * Fetch and parse the subcatalog referenced by an entry
1210 * It tries to be thread safe but by lack of an atomic test and
1211 * set there is a risk of loosing memory.
1212 *
1213 * Returns 0 in case of success, -1 otherwise
1214 */
1215static int
1216xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001217 xmlCatalogEntryPtr children = NULL, doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001218
1219 if (catal == NULL)
1220 return(-1);
1221 if (catal->value == NULL)
1222 return(-1);
1223 if (catal->children != NULL)
1224 return(-1);
1225
Daniel Veillard6990bf32001-08-23 21:17:48 +00001226 if (xmlCatalogXMLFiles != NULL)
1227 children = (xmlCatalogEntryPtr)
1228 xmlHashLookup(xmlCatalogXMLFiles, catal->value);
1229 if (children != NULL) {
1230 catal->children = children;
1231 catal->dealloc = 0;
1232 return(0);
1233 }
1234
Daniel Veillardcda96922001-08-21 10:56:31 +00001235 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001236 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1237 * use the existing catalog, there is no recusivity allowed at
1238 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001239 */
Daniel Veillard6990bf32001-08-23 21:17:48 +00001240 doc = xmlParseXMLCatalogFile(catal->prefer, catal->value);
1241 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001242 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillardcda96922001-08-21 10:56:31 +00001243 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001244 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00001245 if ((catal->type == XML_CATA_CATALOG) &&
1246 (doc->type == XML_CATA_CATALOG)) {
1247 children = doc->children;
1248 doc->children = NULL;
1249 xmlFreeCatalogEntryList(doc);
1250 } else {
1251 children = doc;
1252 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001253
1254 /*
1255 * Where a real test and set would be needed !
1256 */
1257 if (catal->children == NULL) {
1258 catal->children = children;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001259 catal->dealloc = 1;
1260 if (xmlCatalogXMLFiles == NULL)
1261 xmlCatalogXMLFiles = xmlHashCreate(10);
1262 if (xmlCatalogXMLFiles != NULL) {
1263 if (children != NULL)
1264 xmlHashAddEntry(xmlCatalogXMLFiles, catal->value, children);
1265 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001266 } else {
1267 /*
1268 * Another thread filled it before us
1269 */
1270 xmlFreeCatalogEntryList(children);
1271 }
1272 return(0);
1273}
1274
Daniel Veillard75b96822001-10-11 18:59:45 +00001275/************************************************************************
1276 * *
1277 * XML Catalog handling *
1278 * *
1279 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001280
1281/**
1282 * xmlAddXMLCatalog:
1283 * @catal: top of an XML catalog
1284 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001285 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001286 * @replace: the replacement value for the match
1287 *
1288 * Add an entry in the XML catalog, it may overwrite existing but
1289 * different entries.
1290 *
1291 * Returns 0 if successful, -1 otherwise
1292 */
1293static int
1294xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1295 const xmlChar *orig, const xmlChar *replace) {
1296 xmlCatalogEntryPtr cur;
1297 xmlCatalogEntryType typ;
1298
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001299 if ((catal == NULL) ||
1300 ((catal->type != XML_CATA_CATALOG) &&
1301 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001302 return(-1);
1303 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001304 if (typ == XML_CATA_NONE) {
1305 if (xmlDebugCatalogs)
1306 xmlGenericError(xmlGenericErrorContext,
1307 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001308 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001309 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001310
1311 cur = catal->children;
1312 /*
1313 * Might be a simple "update in place"
1314 */
1315 if (cur != NULL) {
1316 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001317 if ((orig != NULL) && (cur->type == typ) &&
1318 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001319 if (xmlDebugCatalogs)
1320 xmlGenericError(xmlGenericErrorContext,
1321 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001322 if (cur->value != NULL)
1323 xmlFree(cur->value);
1324 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001325 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001326 }
1327 if (cur->next == NULL)
1328 break;
1329 cur = cur->next;
1330 }
1331 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001332 if (xmlDebugCatalogs)
1333 xmlGenericError(xmlGenericErrorContext,
1334 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001335 if (cur == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001336 catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001337 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001338 cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillardcda96922001-08-21 10:56:31 +00001339 return(0);
1340}
1341
1342/**
1343 * xmlDelXMLCatalog:
1344 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001345 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001346 *
1347 * Remove entries in the XML catalog where the value or the URI
1348 * is equal to @value
1349 *
1350 * Returns the number of entries removed if successful, -1 otherwise
1351 */
1352static int
1353xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1354 xmlCatalogEntryPtr cur, prev, tmp;
1355 int ret = 0;
1356
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001357 if ((catal == NULL) ||
1358 ((catal->type != XML_CATA_CATALOG) &&
1359 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001360 return(-1);
1361 if (value == NULL)
1362 return(-1);
1363
1364 /*
1365 * Scan the children
1366 */
1367 cur = catal->children;
1368 prev = NULL;
1369 while (cur != NULL) {
1370 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1371 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001372 if (xmlDebugCatalogs) {
1373 if (cur->name != NULL)
1374 xmlGenericError(xmlGenericErrorContext,
1375 "Removing element %s from catalog\n", cur->name);
1376 else
1377 xmlGenericError(xmlGenericErrorContext,
1378 "Removing element %s from catalog\n", cur->value);
1379 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001380 ret++;
1381 tmp = cur;
1382 cur = tmp->next;
1383 if (prev == NULL) {
1384 catal->children = cur;
1385 } else {
1386 prev->next = cur;
1387 }
1388 xmlFreeCatalogEntry(tmp);
1389 continue;
1390 }
1391 prev = cur;
1392 cur = cur->next;
1393 }
1394 return(ret);
1395}
1396
1397/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001398 * xmlCatalogXMLResolve:
1399 * @catal: a catalog list
1400 * @pubId: the public ID string
1401 * @sysId: the system ID string
1402 *
1403 * Do a complete resolution lookup of an External Identifier for a
1404 * list of catalog entries.
1405 *
1406 * Implements (or tries to) 7.1. External Identifier Resolution
1407 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1408 *
1409 * Returns the URI of the resource or NULL if not found
1410 */
1411static xmlChar *
1412xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1413 const xmlChar *sysID) {
1414 xmlChar *ret = NULL;
1415 xmlCatalogEntryPtr cur;
1416 int haveDelegate = 0;
1417 int haveNext = 0;
1418
1419 /*
1420 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1421 */
1422 if (sysID != NULL) {
1423 xmlCatalogEntryPtr rewrite = NULL;
1424 int lenrewrite = 0, len;
1425 cur = catal;
1426 haveDelegate = 0;
1427 while (cur != NULL) {
1428 switch (cur->type) {
1429 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001430 if (xmlStrEqual(sysID, cur->name)) {
1431 if (xmlDebugCatalogs)
1432 xmlGenericError(xmlGenericErrorContext,
1433 "Found system match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001434 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001435 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001436 break;
1437 case XML_CATA_REWRITE_SYSTEM:
1438 len = xmlStrlen(cur->name);
1439 if ((len > lenrewrite) &&
1440 (!xmlStrncmp(sysID, cur->name, len))) {
1441 lenrewrite = len;
1442 rewrite = cur;
1443 }
1444 break;
1445 case XML_CATA_DELEGATE_SYSTEM:
1446 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1447 haveDelegate++;
1448 break;
1449 case XML_CATA_NEXT_CATALOG:
1450 haveNext++;
1451 break;
1452 default:
1453 break;
1454 }
1455 cur = cur->next;
1456 }
1457 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001458 if (xmlDebugCatalogs)
1459 xmlGenericError(xmlGenericErrorContext,
1460 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001461 ret = xmlStrdup(rewrite->value);
1462 if (ret != NULL)
1463 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1464 return(ret);
1465 }
1466 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001467 const xmlChar *delegates[MAX_DELEGATE];
1468 int nbList = 0, i;
1469
Daniel Veillardcda96922001-08-21 10:56:31 +00001470 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001471 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001472 * matches when the list was produced.
1473 */
1474 cur = catal;
1475 while (cur != NULL) {
1476 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1477 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001478 for (i = 0;i < nbList;i++)
1479 if (xmlStrEqual(cur->value, delegates[i]))
1480 break;
1481 if (i < nbList) {
1482 cur = cur->next;
1483 continue;
1484 }
1485 if (nbList < MAX_DELEGATE)
1486 delegates[nbList++] = cur->value;
1487
Daniel Veillardcda96922001-08-21 10:56:31 +00001488 if (cur->children == NULL) {
1489 xmlFetchXMLCatalogFile(cur);
1490 }
1491 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001492 if (xmlDebugCatalogs)
1493 xmlGenericError(xmlGenericErrorContext,
1494 "Trying system delegate %s\n", cur->value);
1495 ret = xmlCatalogListXMLResolve(cur->children, NULL,
1496 sysID);
1497 if (ret != NULL)
1498 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001499 }
1500 }
1501 cur = cur->next;
1502 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001503 /*
1504 * Apply the cut algorithm explained in 4/
1505 */
1506 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001507 }
1508 }
1509 /*
1510 * Then tries 5/ 6/ if a public ID is provided
1511 */
1512 if (pubID != NULL) {
1513 cur = catal;
1514 haveDelegate = 0;
1515 while (cur != NULL) {
1516 switch (cur->type) {
1517 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001518 if (xmlStrEqual(pubID, cur->name)) {
1519 if (xmlDebugCatalogs)
1520 xmlGenericError(xmlGenericErrorContext,
1521 "Found public match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001522 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001523 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001524 break;
1525 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001526 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1527 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001528 haveDelegate++;
1529 break;
1530 case XML_CATA_NEXT_CATALOG:
1531 if (sysID == NULL)
1532 haveNext++;
1533 break;
1534 default:
1535 break;
1536 }
1537 cur = cur->next;
1538 }
1539 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001540 const xmlChar *delegates[MAX_DELEGATE];
1541 int nbList = 0, i;
1542
Daniel Veillardcda96922001-08-21 10:56:31 +00001543 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001544 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001545 * matches when the list was produced.
1546 */
1547 cur = catal;
1548 while (cur != NULL) {
1549 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001550 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1551 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001552
1553 for (i = 0;i < nbList;i++)
1554 if (xmlStrEqual(cur->value, delegates[i]))
1555 break;
1556 if (i < nbList) {
1557 cur = cur->next;
1558 continue;
1559 }
1560 if (nbList < MAX_DELEGATE)
1561 delegates[nbList++] = cur->value;
1562
Daniel Veillardcda96922001-08-21 10:56:31 +00001563 if (cur->children == NULL) {
1564 xmlFetchXMLCatalogFile(cur);
1565 }
1566 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001567 if (xmlDebugCatalogs)
1568 xmlGenericError(xmlGenericErrorContext,
1569 "Trying public delegate %s\n", cur->value);
1570 ret = xmlCatalogListXMLResolve(cur->children, pubID,
1571 NULL);
1572 if (ret != NULL)
1573 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001574 }
1575 }
1576 cur = cur->next;
1577 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001578 /*
1579 * Apply the cut algorithm explained in 4/
1580 */
1581 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001582 }
1583 }
1584 if (haveNext) {
1585 cur = catal;
1586 while (cur != NULL) {
1587 if (cur->type == XML_CATA_NEXT_CATALOG) {
1588 if (cur->children == NULL) {
1589 xmlFetchXMLCatalogFile(cur);
1590 }
1591 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001592 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1593 if (ret != NULL)
1594 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001595 }
1596 }
1597 cur = cur->next;
1598 }
1599 }
1600
1601 return(NULL);
1602}
1603
1604/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001605 * xmlCatalogXMLResolveURI:
1606 * @catal: a catalog list
1607 * @URI: the URI
1608 * @sysId: the system ID string
1609 *
1610 * Do a complete resolution lookup of an External Identifier for a
1611 * list of catalog entries.
1612 *
1613 * Implements (or tries to) 7.2.2. URI Resolution
1614 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1615 *
1616 * Returns the URI of the resource or NULL if not found
1617 */
1618static xmlChar *
1619xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1620 xmlChar *ret = NULL;
1621 xmlCatalogEntryPtr cur;
1622 int haveDelegate = 0;
1623 int haveNext = 0;
1624 xmlCatalogEntryPtr rewrite = NULL;
1625 int lenrewrite = 0, len;
1626
1627 if (catal == NULL)
1628 return(NULL);
1629
1630 if (URI == NULL)
1631 return(NULL);
1632
1633 /*
1634 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1635 */
1636 cur = catal;
1637 haveDelegate = 0;
1638 while (cur != NULL) {
1639 switch (cur->type) {
1640 case XML_CATA_URI:
1641 if (xmlStrEqual(URI, cur->name)) {
1642 if (xmlDebugCatalogs)
1643 xmlGenericError(xmlGenericErrorContext,
1644 "Found URI match %s\n", cur->name);
1645 return(xmlStrdup(cur->value));
1646 }
1647 break;
1648 case XML_CATA_REWRITE_URI:
1649 len = xmlStrlen(cur->name);
1650 if ((len > lenrewrite) &&
1651 (!xmlStrncmp(URI, cur->name, len))) {
1652 lenrewrite = len;
1653 rewrite = cur;
1654 }
1655 break;
1656 case XML_CATA_DELEGATE_URI:
1657 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1658 haveDelegate++;
1659 break;
1660 case XML_CATA_NEXT_CATALOG:
1661 haveNext++;
1662 break;
1663 default:
1664 break;
1665 }
1666 cur = cur->next;
1667 }
1668 if (rewrite != NULL) {
1669 if (xmlDebugCatalogs)
1670 xmlGenericError(xmlGenericErrorContext,
1671 "Using rewriting rule %s\n", rewrite->name);
1672 ret = xmlStrdup(rewrite->value);
1673 if (ret != NULL)
1674 ret = xmlStrcat(ret, &URI[lenrewrite]);
1675 return(ret);
1676 }
1677 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001678 const xmlChar *delegates[MAX_DELEGATE];
1679 int nbList = 0, i;
1680
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001681 /*
1682 * Assume the entries have been sorted by decreasing substring
1683 * matches when the list was produced.
1684 */
1685 cur = catal;
1686 while (cur != NULL) {
1687 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1688 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001689 for (i = 0;i < nbList;i++)
1690 if (xmlStrEqual(cur->value, delegates[i]))
1691 break;
1692 if (i < nbList) {
1693 cur = cur->next;
1694 continue;
1695 }
1696 if (nbList < MAX_DELEGATE)
1697 delegates[nbList++] = cur->value;
1698
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001699 if (cur->children == NULL) {
1700 xmlFetchXMLCatalogFile(cur);
1701 }
1702 if (cur->children != NULL) {
1703 if (xmlDebugCatalogs)
1704 xmlGenericError(xmlGenericErrorContext,
1705 "Trying URI delegate %s\n", cur->value);
1706 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1707 if (ret != NULL)
1708 return(ret);
1709 }
1710 }
1711 cur = cur->next;
1712 }
1713 /*
1714 * Apply the cut algorithm explained in 4/
1715 */
1716 return(XML_CATAL_BREAK);
1717 }
1718 if (haveNext) {
1719 cur = catal;
1720 while (cur != NULL) {
1721 if (cur->type == XML_CATA_NEXT_CATALOG) {
1722 if (cur->children == NULL) {
1723 xmlFetchXMLCatalogFile(cur);
1724 }
1725 if (cur->children != NULL) {
1726 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1727 if (ret != NULL)
1728 return(ret);
1729 }
1730 }
1731 cur = cur->next;
1732 }
1733 }
1734
1735 return(NULL);
1736}
1737
1738/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001739 * xmlCatalogListXMLResolve:
1740 * @catal: a catalog list
1741 * @pubId: the public ID string
1742 * @sysId: the system ID string
1743 *
1744 * Do a complete resolution lookup of an External Identifier for a
1745 * list of catalogs
1746 *
1747 * Implements (or tries to) 7.1. External Identifier Resolution
1748 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1749 *
1750 * Returns the URI of the resource or NULL if not found
1751 */
1752static xmlChar *
1753xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1754 const xmlChar *sysID) {
1755 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001756 xmlChar *urnID = NULL;
1757
1758 if (catal == NULL)
1759 return(NULL);
1760 if ((pubID == NULL) && (sysID == NULL))
1761 return(NULL);
1762
1763 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1764 urnID = xmlCatalogUnWrapURN(pubID);
1765 if (xmlDebugCatalogs) {
1766 if (urnID == NULL)
1767 xmlGenericError(xmlGenericErrorContext,
1768 "Public URN ID %s expanded to NULL\n", pubID);
1769 else
1770 xmlGenericError(xmlGenericErrorContext,
1771 "Public URN ID expanded to %s\n", urnID);
1772 }
1773 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1774 if (urnID != NULL)
1775 xmlFree(urnID);
1776 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001777 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001778 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1779 urnID = xmlCatalogUnWrapURN(sysID);
1780 if (xmlDebugCatalogs) {
1781 if (urnID == NULL)
1782 xmlGenericError(xmlGenericErrorContext,
1783 "System URN ID %s expanded to NULL\n", sysID);
1784 else
1785 xmlGenericError(xmlGenericErrorContext,
1786 "System URN ID expanded to %s\n", urnID);
1787 }
1788 if (pubID == NULL)
1789 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1790 else if (xmlStrEqual(pubID, urnID))
1791 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1792 else {
1793 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1794 }
1795 if (urnID != NULL)
1796 xmlFree(urnID);
1797 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001798 }
1799 while (catal != NULL) {
1800 if (catal->type == XML_CATA_CATALOG) {
1801 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001802 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001803 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001804 if (catal->children != NULL) {
1805 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1806 if (ret != NULL)
1807 return(ret);
1808 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001809 }
1810 catal = catal->next;
1811 }
1812 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001813}
1814
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001815/**
1816 * xmlCatalogListXMLResolveURI:
1817 * @catal: a catalog list
1818 * @URI: the URI
1819 *
1820 * Do a complete resolution lookup of an URI for a list of catalogs
1821 *
1822 * Implements (or tries to) 7.2. URI Resolution
1823 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1824 *
1825 * Returns the URI of the resource or NULL if not found
1826 */
1827static xmlChar *
1828xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1829 xmlChar *ret = NULL;
1830 xmlChar *urnID = NULL;
1831
1832 if (catal == NULL)
1833 return(NULL);
1834 if (URI == NULL)
1835 return(NULL);
1836
1837 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1838 urnID = xmlCatalogUnWrapURN(URI);
1839 if (xmlDebugCatalogs) {
1840 if (urnID == NULL)
1841 xmlGenericError(xmlGenericErrorContext,
1842 "URN ID %s expanded to NULL\n", URI);
1843 else
1844 xmlGenericError(xmlGenericErrorContext,
1845 "URN ID expanded to %s\n", urnID);
1846 }
1847 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1848 if (urnID != NULL)
1849 xmlFree(urnID);
1850 return(ret);
1851 }
1852 while (catal != NULL) {
1853 if (catal->type == XML_CATA_CATALOG) {
1854 if (catal->children == NULL) {
1855 xmlFetchXMLCatalogFile(catal);
1856 }
1857 if (catal->children != NULL) {
1858 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1859 if (ret != NULL)
1860 return(ret);
1861 }
1862 }
1863 catal = catal->next;
1864 }
1865 return(ret);
1866}
1867
Daniel Veillard344cee72001-08-20 00:08:40 +00001868/************************************************************************
1869 * *
1870 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001871 * *
1872 ************************************************************************/
1873
1874
1875#define RAW *cur
1876#define NEXT cur++;
1877#define SKIP(x) cur += x;
1878
1879#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1880
Daniel Veillard75b96822001-10-11 18:59:45 +00001881/**
1882 * xmlParseSGMLCatalogComment:
1883 * @cur: the current character
1884 *
1885 * Skip a comment in an SGML catalog
1886 *
1887 * Returns new current character
1888 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001889static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001890xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001891 if ((cur[0] != '-') || (cur[1] != '-'))
1892 return(cur);
1893 SKIP(2);
1894 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1895 NEXT;
1896 if (cur[0] == 0) {
1897 return(NULL);
1898 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001899 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001900}
1901
Daniel Veillard75b96822001-10-11 18:59:45 +00001902/**
1903 * xmlParseSGMLCatalogPubid:
1904 * @cur: the current character
1905 * @id: the return location
1906 *
1907 * Parse an SGML catalog ID
1908 *
1909 * Returns new current character and store the value in @id
1910 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001911static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001912xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001913 xmlChar *buf = NULL;
1914 int len = 0;
1915 int size = 50;
1916 xmlChar stop;
1917 int count = 0;
1918
1919 *id = NULL;
1920
1921 if (RAW == '"') {
1922 NEXT;
1923 stop = '"';
1924 } else if (RAW == '\'') {
1925 NEXT;
1926 stop = '\'';
1927 } else {
1928 stop = ' ';
1929 }
1930 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1931 if (buf == NULL) {
1932 xmlGenericError(xmlGenericErrorContext,
1933 "malloc of %d byte failed\n", size);
1934 return(NULL);
1935 }
1936 while (xmlIsPubidChar(*cur)) {
1937 if ((*cur == stop) && (stop != ' '))
1938 break;
1939 if ((stop == ' ') && (IS_BLANK(*cur)))
1940 break;
1941 if (len + 1 >= size) {
1942 size *= 2;
1943 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1944 if (buf == NULL) {
1945 xmlGenericError(xmlGenericErrorContext,
1946 "realloc of %d byte failed\n", size);
1947 return(NULL);
1948 }
1949 }
1950 buf[len++] = *cur;
1951 count++;
1952 NEXT;
1953 }
1954 buf[len] = 0;
1955 if (stop == ' ') {
1956 if (!IS_BLANK(*cur)) {
1957 xmlFree(buf);
1958 return(NULL);
1959 }
1960 } else {
1961 if (*cur != stop) {
1962 xmlFree(buf);
1963 return(NULL);
1964 }
1965 NEXT;
1966 }
1967 *id = buf;
1968 return(cur);
1969}
1970
Daniel Veillard75b96822001-10-11 18:59:45 +00001971/**
1972 * xmlParseSGMLCatalogName:
1973 * @cur: the current character
1974 * @name: the return location
1975 *
1976 * Parse an SGML catalog name
1977 *
1978 * Returns new current character and store the value in @name
1979 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001980static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001981xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001982 xmlChar buf[XML_MAX_NAMELEN + 5];
1983 int len = 0;
1984 int c;
1985
1986 *name = NULL;
1987
1988 /*
1989 * Handler for more complex cases
1990 */
1991 c = *cur;
1992 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
1993 return(NULL);
1994 }
1995
1996 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
1997 (c == '.') || (c == '-') ||
1998 (c == '_') || (c == ':'))) {
1999 buf[len++] = c;
2000 cur++;
2001 c = *cur;
2002 if (len >= XML_MAX_NAMELEN)
2003 return(NULL);
2004 }
2005 *name = xmlStrndup(buf, len);
2006 return(cur);
2007}
2008
Daniel Veillard75b96822001-10-11 18:59:45 +00002009/**
2010 * xmlGetSGMLCatalogEntryType:
2011 * @name: the entry name
2012 *
2013 * Get the Catalog entry type for a given SGML Catalog name
2014 *
2015 * Returns Catalog entry type
2016 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002017static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002018xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002019 xmlCatalogEntryType type = XML_CATA_NONE;
2020 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2021 type = SGML_CATA_SYSTEM;
2022 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2023 type = SGML_CATA_PUBLIC;
2024 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2025 type = SGML_CATA_DELEGATE;
2026 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2027 type = SGML_CATA_ENTITY;
2028 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2029 type = SGML_CATA_DOCTYPE;
2030 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2031 type = SGML_CATA_LINKTYPE;
2032 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2033 type = SGML_CATA_NOTATION;
2034 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2035 type = SGML_CATA_SGMLDECL;
2036 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2037 type = SGML_CATA_DOCUMENT;
2038 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2039 type = SGML_CATA_CATALOG;
2040 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2041 type = SGML_CATA_BASE;
2042 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2043 type = SGML_CATA_DELEGATE;
2044 return(type);
2045}
2046
Daniel Veillard75b96822001-10-11 18:59:45 +00002047/**
2048 * xmlParseSGMLCatalog:
2049 * @catal: the SGML Catalog
2050 * @value: the content of the SGML Catalog serialization
2051 * @file: the filepath for the catalog
2052 * @super: should this be handled as a Super Catalog in which case
2053 * parsing is not recursive
2054 *
2055 * Parse an SGML catalog content and fill up the @catal hash table with
2056 * the new entries found.
2057 *
2058 * Returns 0 in case of success, -1 in case of error.
2059 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002060static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002061xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2062 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002063 const xmlChar *cur = value;
2064 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002065 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002066
2067 if ((cur == NULL) || (file == NULL))
2068 return(-1);
2069 base = xmlStrdup((const xmlChar *) file);
2070
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002071 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002072 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002073 if (cur[0] == 0)
2074 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002075 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002076 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002077 if (cur == NULL) {
2078 /* error */
2079 break;
2080 }
2081 } else {
2082 xmlChar *sysid = NULL;
2083 xmlChar *name = NULL;
2084 xmlCatalogEntryType type = XML_CATA_NONE;
2085
Daniel Veillardcda96922001-08-21 10:56:31 +00002086 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002087 if (name == NULL) {
2088 /* error */
2089 break;
2090 }
2091 if (!IS_BLANK(*cur)) {
2092 /* error */
2093 break;
2094 }
2095 SKIP_BLANKS;
2096 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002097 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002098 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002099 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002100 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002101 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002102 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002103 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002104 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002105 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002106 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002107 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002108 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002109 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002110 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002111 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002112 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002113 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002114 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002115 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002116 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002117 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002118 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002119 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002120 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2121 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002122 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002123 if (name == NULL) {
2124 /* error */
2125 break;
2126 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002127 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002128 continue;
2129 }
2130 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002131 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002132
2133 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002134 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002135 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002136 type = SGML_CATA_PENTITY;
2137 case SGML_CATA_PENTITY:
2138 case SGML_CATA_DOCTYPE:
2139 case SGML_CATA_LINKTYPE:
2140 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002141 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002142 if (cur == NULL) {
2143 /* error */
2144 break;
2145 }
2146 if (!IS_BLANK(*cur)) {
2147 /* error */
2148 break;
2149 }
2150 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002151 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002152 if (cur == NULL) {
2153 /* error */
2154 break;
2155 }
2156 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002157 case SGML_CATA_PUBLIC:
2158 case SGML_CATA_SYSTEM:
2159 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002160 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002161 if (cur == NULL) {
2162 /* error */
2163 break;
2164 }
2165 if (!IS_BLANK(*cur)) {
2166 /* error */
2167 break;
2168 }
2169 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002170 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002171 if (cur == NULL) {
2172 /* error */
2173 break;
2174 }
2175 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002176 case SGML_CATA_BASE:
2177 case SGML_CATA_CATALOG:
2178 case SGML_CATA_DOCUMENT:
2179 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002180 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002181 if (cur == NULL) {
2182 /* error */
2183 break;
2184 }
2185 break;
2186 default:
2187 break;
2188 }
2189 if (cur == NULL) {
2190 if (name != NULL)
2191 xmlFree(name);
2192 if (sysid != NULL)
2193 xmlFree(sysid);
2194 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002195 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002196 if (base != NULL)
2197 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002198 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002199 } else if ((type == SGML_CATA_PUBLIC) ||
2200 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002201 xmlChar *filename;
2202
2203 filename = xmlBuildURI(sysid, base);
2204 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002205 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002206
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002207 entry = xmlNewCatalogEntry(type, name, filename,
2208 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002209 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002210 if (res < 0) {
2211 xmlFreeCatalogEntry(entry);
2212 }
2213 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002214 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002215
Daniel Veillard344cee72001-08-20 00:08:40 +00002216 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002217 if (super) {
2218 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002219
Daniel Veillard82d75332001-10-08 15:01:59 +00002220 entry = xmlNewCatalogEntry(type, sysid, NULL,
2221 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002222 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002223 if (res < 0) {
2224 xmlFreeCatalogEntry(entry);
2225 }
2226 } else {
2227 xmlChar *filename;
2228
2229 filename = xmlBuildURI(sysid, base);
2230 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002231 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002232 xmlFree(filename);
2233 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002234 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002235 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002236 /*
2237 * drop anything else we won't handle it
2238 */
2239 if (name != NULL)
2240 xmlFree(name);
2241 if (sysid != NULL)
2242 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002243 }
2244 }
2245 if (base != NULL)
2246 xmlFree(base);
2247 if (cur == NULL)
2248 return(-1);
2249 return(0);
2250}
2251
Daniel Veillard75b96822001-10-11 18:59:45 +00002252/************************************************************************
2253 * *
2254 * SGML Catalog handling *
2255 * *
2256 ************************************************************************/
2257
Daniel Veillardcda96922001-08-21 10:56:31 +00002258/**
2259 * xmlCatalogGetSGMLPublic:
2260 * @catal: an SGML catalog hash
2261 * @pubId: the public ID string
2262 *
2263 * Try to lookup the system ID associated to a public ID
2264 *
2265 * Returns the system ID if found or NULL otherwise.
2266 */
2267static const xmlChar *
2268xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2269 xmlCatalogEntryPtr entry;
2270
2271 if (catal == NULL)
2272 return(NULL);
2273
2274 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2275 if (entry == NULL)
2276 return(NULL);
2277 if (entry->type == SGML_CATA_PUBLIC)
2278 return(entry->value);
2279 return(NULL);
2280}
2281
2282/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002283 * xmlCatalogGetSGMLSystem:
2284 * @catal: an SGML catalog hash
2285 * @sysId: the public ID string
2286 *
2287 * Try to lookup the catalog local reference for a system ID
2288 *
2289 * Returns the system ID if found or NULL otherwise.
2290 */
2291static const xmlChar *
2292xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2293 xmlCatalogEntryPtr entry;
2294
2295 if (catal == NULL)
2296 return(NULL);
2297
2298 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2299 if (entry == NULL)
2300 return(NULL);
2301 if (entry->type == SGML_CATA_SYSTEM)
2302 return(entry->value);
2303 return(NULL);
2304}
2305
2306/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002307 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002308 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002309 * @pubId: the public ID string
2310 * @sysId: the system ID string
2311 *
2312 * Do a complete resolution lookup of an External Identifier
2313 *
2314 * Returns the URI of the resource or NULL if not found
2315 */
2316static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002317xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2318 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002319 const xmlChar *ret = NULL;
2320
Daniel Veillard75b96822001-10-11 18:59:45 +00002321 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002322 return(NULL);
2323
2324 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002325 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002326 if (ret != NULL)
2327 return(ret);
2328 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002329 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002330 return(NULL);
2331}
2332
Daniel Veillarda7374592001-05-10 14:17:55 +00002333/************************************************************************
2334 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002335 * Specific Public interfaces *
2336 * *
2337 ************************************************************************/
2338
2339/**
2340 * xmlLoadSGMLSuperCatalog:
2341 * @filename: a file path
2342 *
2343 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2344 * references. This is only needed for manipulating SGML Super Catalogs
2345 * like adding and removing CATALOG or DELEGATE entries.
2346 *
2347 * Returns the catalog parsed or NULL in case of error
2348 */
2349xmlCatalogPtr
2350xmlLoadSGMLSuperCatalog(const char *filename)
2351{
2352 xmlChar *content;
2353 xmlCatalogPtr catal;
2354 int ret;
2355
2356 content = xmlLoadFileContent(filename);
2357 if (content == NULL)
2358 return(NULL);
2359
2360 catal = xmlNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2361 if (catal == NULL) {
2362 xmlFree(content);
2363 return(NULL);
2364 }
2365
2366 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2367 xmlFree(content);
2368 if (ret < 0) {
2369 xmlFreeCatalog(catal);
2370 return(NULL);
2371 }
2372 return (catal);
2373}
2374
2375/**
2376 * xmlLoadACatalog:
2377 * @filename: a file path
2378 *
2379 * Load the catalog and build the associated data structures.
2380 * This can be either an XML Catalog or an SGML Catalog
2381 * It will recurse in SGML CATALOG entries. On the other hand XML
2382 * Catalogs are not handled recursively.
2383 *
2384 * Returns the catalog parsed or NULL in case of error
2385 */
2386xmlCatalogPtr
2387xmlLoadACatalog(const char *filename)
2388{
2389 xmlChar *content;
2390 xmlChar *first;
2391 xmlCatalogPtr catal;
2392 int ret;
2393
2394 content = xmlLoadFileContent(filename);
2395 if (content == NULL)
2396 return(NULL);
2397
2398
2399 first = content;
2400
2401 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2402 (!(((*first >= 'A') && (*first <= 'Z')) ||
2403 ((*first >= 'a') && (*first <= 'z')))))
2404 first++;
2405
2406 if (*first != '<') {
2407 catal = xmlNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2408 if (catal == NULL) {
2409 xmlFree(content);
2410 return(NULL);
2411 }
2412 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2413 if (ret < 0) {
2414 xmlFreeCatalog(catal);
2415 xmlFree(content);
2416 return(NULL);
2417 }
2418 } else {
2419 catal = xmlNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2420 if (catal == NULL) {
2421 xmlFree(content);
2422 return(NULL);
2423 }
2424 catal->xml =
2425 xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
2426 }
2427 xmlFree(content);
2428 return (catal);
2429}
2430
2431/**
2432 * xmlExpandCatalog:
2433 * @catal: a catalog
2434 * @filename: a file path
2435 *
2436 * Load the catalog and expand the existing catal structure.
2437 * This can be either an XML Catalog or an SGML Catalog
2438 *
2439 * Returns 0 in case of success, -1 in case of error
2440 */
2441int
2442xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2443{
2444 xmlChar *content;
2445 int ret;
2446
2447 if ((catal == NULL) || (filename == NULL))
2448 return(-1);
2449
2450 content = xmlLoadFileContent(filename);
2451 if (content == NULL)
2452 return(-1);
2453
2454
2455 if (catal->type == XML_SGML_CATALOG_TYPE) {
2456 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2457 if (ret < 0) {
2458 xmlFree(content);
2459 return(-1);
2460 }
2461 } else {
2462 xmlCatalogEntryPtr tmp, cur;
2463 tmp = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
2464
2465 /* @@ THREADING LOCK catal @@ */
2466 cur = catal->xml;
2467 if (cur == NULL) {
2468 catal->xml = tmp;
2469 } else {
2470 while (cur->next != NULL) cur = cur->next;
2471 cur->next = tmp;
2472 }
2473 /* @@ THREADING RELEASE catal @@ */
2474 }
2475 xmlFree(content);
2476 return (0);
2477}
2478
2479/**
2480 * xmlACatalogResolveSystem:
2481 * @catal: a Catalog
2482 * @sysId: the public ID string
2483 *
2484 * Try to lookup the catalog resource for a system ID
2485 *
2486 * Returns the system ID if found or NULL otherwise, the value returned
2487 * must be freed by the caller.
2488 */
2489xmlChar *
2490xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2491 xmlChar *ret = NULL;
2492
2493 if ((sysID == NULL) || (catal == NULL))
2494 return(NULL);
2495
2496 if (xmlDebugCatalogs)
2497 xmlGenericError(xmlGenericErrorContext,
2498 "Resolve sysID %s\n", sysID);
2499
2500 if (catal->type == XML_XML_CATALOG_TYPE) {
2501 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2502 if (ret == XML_CATAL_BREAK)
2503 ret = NULL;
2504 } else {
2505 const xmlChar *sgml;
2506
2507 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2508 if (sgml != NULL)
2509 ret = xmlStrdup(sgml);
2510 }
2511 return(ret);
2512}
2513
2514/**
2515 * xmlACatalogResolvePublic:
2516 * @catal: a Catalog
2517 * @pubId: the public ID string
2518 *
2519 * Try to lookup the system ID associated to a public ID in that catalog
2520 *
2521 * Returns the system ID if found or NULL otherwise, the value returned
2522 * must be freed by the caller.
2523 */
2524xmlChar *
2525xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2526 xmlChar *ret = NULL;
2527
2528 if ((pubID == NULL) || (catal == NULL))
2529 return(NULL);
2530
2531 if (xmlDebugCatalogs)
2532 xmlGenericError(xmlGenericErrorContext,
2533 "Resolve pubID %s\n", pubID);
2534
2535 if (catal->type == XML_XML_CATALOG_TYPE) {
2536 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2537 if (ret == XML_CATAL_BREAK)
2538 ret = NULL;
2539 } else {
2540 const xmlChar *sgml;
2541
2542 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2543 if (sgml != NULL)
2544 ret = xmlStrdup(sgml);
2545 }
2546 return(ret);
2547}
2548
2549/**
2550 * xmlACatalogResolve:
2551 * @catal: a Catalog
2552 * @pubId: the public ID string
2553 * @sysId: the system ID string
2554 *
2555 * Do a complete resolution lookup of an External Identifier
2556 *
2557 * Returns the URI of the resource or NULL if not found, it must be freed
2558 * by the caller.
2559 */
2560xmlChar *
2561xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2562 const xmlChar * sysID)
2563{
2564 xmlChar *ret = NULL;
2565
2566 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2567 return (NULL);
2568
2569 if (xmlDebugCatalogs) {
2570 if (pubID != NULL) {
2571 xmlGenericError(xmlGenericErrorContext,
2572 "Resolve: pubID %s\n", pubID);
2573 } else {
2574 xmlGenericError(xmlGenericErrorContext,
2575 "Resolve: sysID %s\n", sysID);
2576 }
2577 }
2578
2579 if (catal->type == XML_XML_CATALOG_TYPE) {
2580 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2581 if (ret == XML_CATAL_BREAK)
2582 ret = NULL;
2583 } else {
2584 const xmlChar *sgml;
2585
2586 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2587 if (sgml != NULL)
2588 ret = xmlStrdup(sgml);
2589 }
2590 return (ret);
2591}
2592
2593/**
2594 * xmlACatalogResolveURI:
2595 * @catal: a Catalog
2596 * @pubId: the URI
2597 *
2598 * Do a complete resolution lookup of an URI
2599 *
2600 * Returns the URI of the resource or NULL if not found, it must be freed
2601 * by the caller.
2602 */
2603xmlChar *
2604xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2605 xmlChar *ret = NULL;
2606
2607 if ((URI == NULL) || (catal == NULL))
2608 return(NULL);
2609
2610 if (catal->type == XML_XML_CATALOG_TYPE)
2611 xmlGenericError(xmlGenericErrorContext,
2612 "Resolve URI %s\n", URI);
2613
2614 if (catal->type == XML_XML_CATALOG_TYPE) {
2615 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2616 if (ret == XML_CATAL_BREAK)
2617 ret = NULL;
2618 } else {
2619 const xmlChar *sgml;
2620
2621 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2622 if (sgml != NULL)
2623 sgml = xmlStrdup(sgml);
2624 }
2625 return(ret);
2626}
2627
2628/**
2629 * xmlACatalogDump:
2630 * @catal: a Catalog
2631 * @out: the file.
2632 *
2633 * Free up all the memory associated with catalogs
2634 */
2635void
2636xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
2637 if (out == NULL)
2638 return;
2639
2640 if (catal->type == XML_XML_CATALOG_TYPE) {
2641 xmlDumpXMLCatalog(out, catal->xml);
2642 } else {
2643 xmlHashScan(catal->sgml,
2644 (xmlHashScanner) xmlCatalogDumpEntry, out);
2645 }
2646}
2647
2648/**
2649 * xmlACatalogAdd:
2650 * @catal: a Catalog
2651 * @type: the type of record to add to the catalog
2652 * @orig: the system, public or prefix to match
2653 * @replace: the replacement value for the match
2654 *
2655 * Add an entry in the catalog, it may overwrite existing but
2656 * different entries.
2657 *
2658 * Returns 0 if successful, -1 otherwise
2659 */
2660int
2661xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2662 const xmlChar * orig, const xmlChar * replace)
2663{
2664 int res = -1;
2665
2666 if (catal == NULL)
2667 return(-1);
2668
2669 if (catal->type == XML_XML_CATALOG_TYPE) {
2670 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2671 } else {
2672 xmlCatalogEntryType cattype;
2673
2674 cattype = xmlGetSGMLCatalogEntryType(type);
2675 if (cattype != XML_CATA_NONE) {
2676 xmlCatalogEntryPtr entry;
2677
2678 entry = xmlNewCatalogEntry(cattype, orig, replace,
2679 XML_CATA_PREFER_NONE);
2680 res = xmlHashAddEntry(catal->sgml, orig, entry);
2681 }
2682 }
2683 return (res);
2684}
2685
2686/**
2687 * xmlACatalogRemove:
2688 * @catal: a Catalog
2689 * @value: the value to remove
2690 *
2691 * Remove an entry from the catalog
2692 *
2693 * Returns the number of entries removed if successful, -1 otherwise
2694 */
2695int
2696xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2697 int res = -1;
2698
2699 if ((catal == NULL) || (value == NULL))
2700 return(-1);
2701
2702 if (catal->type == XML_XML_CATALOG_TYPE) {
2703 res = xmlDelXMLCatalog(catal->xml, value);
2704 } else {
2705 res = xmlHashRemoveEntry(catal->sgml, value,
2706 (xmlHashDeallocator) xmlFreeCatalogEntry);
2707 if (res == 0)
2708 res = 1;
2709 }
2710 return(res);
2711}
2712
2713/************************************************************************
2714 * *
2715 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002716 * *
2717 ************************************************************************/
2718
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002719/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002720 * xmlInitializeCatalog:
2721 *
2722 * Do the catalog initialization.
2723 * TODO: this function is not thread safe, catalog initialization should
2724 * preferably be done once at startup
2725 */
2726void
2727xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002728 if (xmlCatalogInitialized != 0)
2729 return;
2730
2731 if (getenv("XML_DEBUG_CATALOG"))
2732 xmlDebugCatalogs = 1;
Daniel Veillard75b96822001-10-11 18:59:45 +00002733 if (xmlDefaultCatalog == NULL) {
2734 const char *catalogs;
2735 xmlCatalogPtr catal;
2736
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002737 catalogs = getenv("XML_CATALOG_FILES");
2738 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002739 catalogs = XML_XML_DEFAULT_CATALOG;
2740
2741 catal = xmlNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2742 if (catal == NULL)
2743 return;
2744
2745 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002746 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002747
2748 xmlDefaultCatalog = catal;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002749 }
2750
2751 xmlCatalogInitialized = 1;
2752}
2753
Daniel Veillard82d75332001-10-08 15:01:59 +00002754
2755/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002756 * xmlLoadCatalog:
2757 * @filename: a file path
2758 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002759 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002760 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002761 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002762 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002763 *
2764 * Returns 0 in case of success -1 in case of error
2765 */
2766int
Daniel Veillard16756b62001-10-01 07:36:25 +00002767xmlLoadCatalog(const char *filename)
2768{
Daniel Veillard75b96822001-10-11 18:59:45 +00002769 int ret;
2770 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002771
Daniel Veillard75b96822001-10-11 18:59:45 +00002772 if (xmlDefaultCatalog == NULL) {
2773 catal = xmlLoadACatalog(filename);
2774 if (catal == NULL)
2775 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002776
Daniel Veillard75b96822001-10-11 18:59:45 +00002777 xmlDefaultCatalog = catal;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002778
Daniel Veillard75b96822001-10-11 18:59:45 +00002779 /*
2780 * Need to be done after ...
2781 */
2782 if (!xmlCatalogInitialized)
2783 xmlInitializeCatalog();
2784 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002785 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002786
Daniel Veillard75b96822001-10-11 18:59:45 +00002787 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
2788 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002789}
2790
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002791/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002792 * xmlLoadCatalogs:
2793 * @paths: a list of file path separated by ':' or spaces
2794 *
2795 * Load the catalogs and makes their definitions effective for the default
2796 * external entity loader.
2797 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002798 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002799 */
2800void
2801xmlLoadCatalogs(const char *pathss) {
2802 const char *cur;
2803 const char *paths;
2804 xmlChar *path;
2805
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002806 if (pathss == NULL)
2807 return;
2808
Daniel Veillard81418e32001-05-22 15:08:55 +00002809 cur = pathss;
2810 while ((cur != NULL) && (*cur != 0)) {
2811 while (IS_BLANK(*cur)) cur++;
2812 if (*cur != 0) {
2813 paths = cur;
2814 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2815 cur++;
2816 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2817 if (path != NULL) {
2818 xmlLoadCatalog((const char *) path);
2819 xmlFree(path);
2820 }
2821 }
2822 while (*cur == ':')
2823 cur++;
2824 }
2825}
2826
Daniel Veillarda7374592001-05-10 14:17:55 +00002827/**
2828 * xmlCatalogCleanup:
2829 *
2830 * Free up all the memory associated with catalogs
2831 */
2832void
2833xmlCatalogCleanup(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002834 if (xmlDebugCatalogs)
2835 xmlGenericError(xmlGenericErrorContext,
2836 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002837 if (xmlCatalogXMLFiles != NULL)
2838 xmlHashFree(xmlCatalogXMLFiles, NULL);
2839 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002840 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002841 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002842 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002843 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002844 xmlCatalogInitialized = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00002845}
2846
2847/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002848 * xmlCatalogResolveSystem:
2849 * @sysId: the public ID string
2850 *
2851 * Try to lookup the catalog resource for a system ID
2852 *
2853 * Returns the system ID if found or NULL otherwise, the value returned
2854 * must be freed by the caller.
2855 */
2856xmlChar *
2857xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002858 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002859
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002860 if (!xmlCatalogInitialized)
2861 xmlInitializeCatalog();
2862
Daniel Veillard75b96822001-10-11 18:59:45 +00002863 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
2864 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002865}
2866
2867/**
2868 * xmlCatalogResolvePublic:
2869 * @pubId: the public ID string
2870 *
2871 * Try to lookup the system ID associated to a public ID
2872 *
2873 * Returns the system ID if found or NULL otherwise, the value returned
2874 * must be freed by the caller.
2875 */
2876xmlChar *
2877xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002878 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002879
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002880 if (!xmlCatalogInitialized)
2881 xmlInitializeCatalog();
2882
Daniel Veillard75b96822001-10-11 18:59:45 +00002883 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
2884 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002885}
Daniel Veillard344cee72001-08-20 00:08:40 +00002886
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002887/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002888 * xmlCatalogResolve:
2889 * @pubId: the public ID string
2890 * @sysId: the system ID string
2891 *
2892 * Do a complete resolution lookup of an External Identifier
2893 *
2894 * Returns the URI of the resource or NULL if not found, it must be freed
2895 * by the caller.
2896 */
2897xmlChar *
2898xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002899 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002900
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002901 if (!xmlCatalogInitialized)
2902 xmlInitializeCatalog();
2903
Daniel Veillard75b96822001-10-11 18:59:45 +00002904 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
2905 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002906}
2907
2908/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002909 * xmlCatalogResolveURI:
2910 * @pubId: the URI
2911 *
2912 * Do a complete resolution lookup of an URI
2913 *
2914 * Returns the URI of the resource or NULL if not found, it must be freed
2915 * by the caller.
2916 */
2917xmlChar *
2918xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002919 xmlChar *ret;
2920
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002921 if (!xmlCatalogInitialized)
2922 xmlInitializeCatalog();
2923
Daniel Veillard75b96822001-10-11 18:59:45 +00002924 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
2925 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002926}
2927
2928/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002929 * xmlCatalogDump:
2930 * @out: the file.
2931 *
2932 * Free up all the memory associated with catalogs
2933 */
2934void
2935xmlCatalogDump(FILE *out) {
2936 if (out == NULL)
2937 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00002938
Daniel Veillard75b96822001-10-11 18:59:45 +00002939 if (!xmlCatalogInitialized)
2940 xmlInitializeCatalog();
2941
2942 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00002943}
2944
2945/**
2946 * xmlCatalogAdd:
2947 * @type: the type of record to add to the catalog
2948 * @orig: the system, public or prefix to match
2949 * @replace: the replacement value for the match
2950 *
2951 * Add an entry in the catalog, it may overwrite existing but
2952 * different entries.
Daniel Veillard75b96822001-10-11 18:59:45 +00002953 * If called before any other catalo routine, allows to override the
2954 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00002955 *
2956 * Returns 0 if successful, -1 otherwise
2957 */
2958int
2959xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
2960 int res = -1;
2961
Daniel Veillard75b96822001-10-11 18:59:45 +00002962 /*
2963 * Specific case where one want to override the default catalog
2964 * put in place by xmlInitializeCatalog();
2965 */
2966 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00002967 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002968 xmlDefaultCatalog = xmlNewCatalog(XML_XML_CATALOG_TYPE,
2969 xmlCatalogDefaultPrefer);
2970 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2971 orig, xmlCatalogDefaultPrefer);
2972
2973 if (!xmlCatalogInitialized)
2974 xmlInitializeCatalog();
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00002975 return(0);
2976 }
2977
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002978 if (!xmlCatalogInitialized)
2979 xmlInitializeCatalog();
2980
Daniel Veillard75b96822001-10-11 18:59:45 +00002981 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard344cee72001-08-20 00:08:40 +00002982 return(res);
2983}
2984
2985/**
2986 * xmlCatalogRemove:
2987 * @value: the value to remove
2988 *
2989 * Remove an entry from the catalog
2990 *
Daniel Veillard82d75332001-10-08 15:01:59 +00002991 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00002992 */
2993int
2994xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002995 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00002996
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002997 if (!xmlCatalogInitialized)
2998 xmlInitializeCatalog();
2999
Daniel Veillard75b96822001-10-11 18:59:45 +00003000 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillardcda96922001-08-21 10:56:31 +00003001 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003002}
3003
3004/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003005 * xmlCatalogConvert:
3006 *
3007 * Convert all the SGML catalog entries as XML ones
3008 *
3009 * Returns the number of entries converted if successful, -1 otherwise
3010 */
3011int
3012xmlCatalogConvert(void) {
3013 int res = -1;
3014
3015 if (!xmlCatalogInitialized)
3016 xmlInitializeCatalog();
3017
Daniel Veillard75b96822001-10-11 18:59:45 +00003018 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003019 return(res);
3020}
3021
Daniel Veillard75b96822001-10-11 18:59:45 +00003022/************************************************************************
3023 * *
3024 * Public interface manipulating the common preferences *
3025 * *
3026 ************************************************************************/
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003027/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003028 * xmlCatalogGetDefaults:
3029 *
3030 * Used to get the user preference w.r.t. to what catalogs should
3031 * be accepted
3032 *
3033 * Returns the current xmlCatalogAllow value
3034 */
3035xmlCatalogAllow
3036xmlCatalogGetDefaults(void) {
3037 return(xmlCatalogDefaultAllow);
3038}
3039
3040/**
3041 * xmlCatalogSetDefaults:
3042 *
3043 * Used to set the user preference w.r.t. to what catalogs should
3044 * be accepted
3045 */
3046void
3047xmlCatalogSetDefaults(xmlCatalogAllow allow) {
3048 if (!xmlCatalogInitialized)
3049 xmlInitializeCatalog();
3050 if (xmlDebugCatalogs) {
3051 switch (allow) {
3052 case XML_CATA_ALLOW_NONE:
3053 xmlGenericError(xmlGenericErrorContext,
3054 "Disabling catalog usage\n");
3055 break;
3056 case XML_CATA_ALLOW_GLOBAL:
3057 xmlGenericError(xmlGenericErrorContext,
3058 "Allowing only global catalogs\n");
3059 break;
3060 case XML_CATA_ALLOW_DOCUMENT:
3061 xmlGenericError(xmlGenericErrorContext,
3062 "Allowing only catalogs from the document\n");
3063 break;
3064 case XML_CATA_ALLOW_ALL:
3065 xmlGenericError(xmlGenericErrorContext,
3066 "Allowing all catalogs\n");
3067 break;
3068 }
3069 }
3070 xmlCatalogDefaultAllow = allow;
3071}
3072
3073/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003074 * xmlCatalogSetDefaultPrefer:
3075 * @prefer: the default preference for delegation
3076 *
3077 * Allows to set the preference between public and system for deletion
3078 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003079 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003080 *
3081 * Returns the previous value of the default preference for delegation
3082 */
3083xmlCatalogPrefer
3084xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3085 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3086
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003087 if (!xmlCatalogInitialized)
3088 xmlInitializeCatalog();
3089 if (prefer == XML_CATA_PREFER_NONE)
3090 return(ret);
3091
3092 if (xmlDebugCatalogs) {
3093 switch (prefer) {
3094 case XML_CATA_PREFER_PUBLIC:
3095 xmlGenericError(xmlGenericErrorContext,
3096 "Setting catalog preference to PUBLIC\n");
3097 break;
3098 case XML_CATA_PREFER_SYSTEM:
3099 xmlGenericError(xmlGenericErrorContext,
3100 "Setting catalog preference to SYSTEM\n");
3101 break;
3102 case XML_CATA_PREFER_NONE:
3103 break;
3104 }
3105 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003106 xmlCatalogDefaultPrefer = prefer;
3107 return(ret);
3108}
3109
3110/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003111 * xmlCatalogSetDebug:
3112 * @level: the debug level of catalogs required
3113 *
3114 * Used to set the debug level for catalog operation, 0 disable
3115 * debugging, 1 enable it
3116 *
3117 * Returns the previous value of the catalog debugging level
3118 */
3119int
3120xmlCatalogSetDebug(int level) {
3121 int ret = xmlDebugCatalogs;
3122
3123 if (level <= 0)
3124 xmlDebugCatalogs = 0;
3125 else
3126 xmlDebugCatalogs = level;
3127 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003128}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003129
Daniel Veillard75b96822001-10-11 18:59:45 +00003130/************************************************************************
3131 * *
3132 * Minimal interfaces used for per-document catalogs by the parser *
3133 * *
3134 ************************************************************************/
3135
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003136/**
3137 * xmlCatalogFreeLocal:
3138 * @catalogs: a document's list of catalogs
3139 *
3140 * Free up the memory associated to the catalog list
3141 */
3142void
3143xmlCatalogFreeLocal(void *catalogs) {
3144 xmlCatalogEntryPtr catal;
3145
3146 catal = (xmlCatalogEntryPtr) catalogs;
3147 if (catal != NULL)
3148 xmlFreeCatalogEntryList(catal);
3149}
3150
3151
3152/**
3153 * xmlCatalogAddLocal:
3154 * @catalogs: a document's list of catalogs
3155 * @URL: the URL to a new local catalog
3156 *
3157 * Add the new entry to the catalog list
3158 *
3159 * Returns the updated list
3160 */
3161void *
3162xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3163 xmlCatalogEntryPtr catal, add;
3164
3165 if (!xmlCatalogInitialized)
3166 xmlInitializeCatalog();
3167 if (URL == NULL)
3168 return(catalogs);
3169
3170 if (xmlDebugCatalogs)
3171 xmlGenericError(xmlGenericErrorContext,
3172 "Adding document catalog %s\n", URL);
3173
3174 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
3175 xmlCatalogDefaultPrefer);
3176 if (add == NULL)
3177 return(catalogs);
3178
3179 catal = (xmlCatalogEntryPtr) catalogs;
3180 if (catal == NULL)
3181 return((void *) add);
3182
3183 while (catal->next != NULL)
3184 catal = catal->next;
3185 catal->next = add;
3186 return(catalogs);
3187}
3188
3189/**
3190 * xmlCatalogLocalResolve:
3191 * @catalogs: a document's list of catalogs
3192 * @pubId: the public ID string
3193 * @sysId: the system ID string
3194 *
3195 * Do a complete resolution lookup of an External Identifier using a
3196 * document's private catalog list
3197 *
3198 * Returns the URI of the resource or NULL if not found, it must be freed
3199 * by the caller.
3200 */
3201xmlChar *
3202xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3203 const xmlChar *sysID) {
3204 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003205 xmlChar *ret;
3206
3207 if ((pubID == NULL) && (sysID == NULL))
3208 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003209
3210 if (!xmlCatalogInitialized)
3211 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003212
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003213 if (xmlDebugCatalogs) {
3214 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003215 xmlGenericError(xmlGenericErrorContext,
3216 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003217 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003218 xmlGenericError(xmlGenericErrorContext,
3219 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003220 }
3221 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003222
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003223 catal = (xmlCatalogEntryPtr) catalogs;
3224 if (catal == NULL)
3225 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003226 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3227 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3228 return(ret);
3229 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003230}
3231
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003232/**
3233 * xmlCatalogLocalResolveURI:
3234 * @catalogs: a document's list of catalogs
3235 * @pubId: the URI
3236 *
3237 * Do a complete resolution lookup of an URI using a
3238 * document's private catalog list
3239 *
3240 * Returns the URI of the resource or NULL if not found, it must be freed
3241 * by the caller.
3242 */
3243xmlChar *
3244xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3245 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003246 xmlChar *ret;
3247
3248 if (URI == NULL)
3249 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003250
3251 if (!xmlCatalogInitialized)
3252 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003253
3254 if (xmlDebugCatalogs)
3255 xmlGenericError(xmlGenericErrorContext,
3256 "Resolve URI %s\n", URI);
3257
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003258 catal = (xmlCatalogEntryPtr) catalogs;
3259 if (catal == NULL)
3260 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003261 ret = xmlCatalogListXMLResolveURI(catal, URI);
3262 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3263 return(ret);
3264 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003265}
3266
Daniel Veillard75b96822001-10-11 18:59:45 +00003267/************************************************************************
3268 * *
3269 * Deprecated interfaces *
3270 * *
3271 ************************************************************************/
3272/**
3273 * xmlCatalogGetSystem:
3274 * @pubId: the public ID string
3275 *
3276 * Try to lookup the system ID associated to a public ID
3277 * DEPRECATED, use xmlCatalogResolveSystem()
3278 *
3279 * Returns the system ID if found or NULL otherwise.
3280 */
3281const xmlChar *
3282xmlCatalogGetSystem(const xmlChar *sysID) {
3283 xmlChar *ret;
3284 static xmlChar result[1000];
3285 static int msg = 0;
3286
3287 if (msg == 0) {
3288 xmlGenericError(xmlGenericErrorContext,
3289 "Use of deprecated xmlCatalogGetSystem() call\n");
3290 msg++;
3291 }
3292
3293 if (sysID == NULL)
3294 return(NULL);
3295
3296 if (!xmlCatalogInitialized)
3297 xmlInitializeCatalog();
3298
3299 /*
3300 * Check first the XML catalogs
3301 */
3302 if (xmlDefaultCatalog != NULL) {
3303 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3304 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3305 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3306 result[sizeof(result) - 1] = 0;
3307 return(result);
3308 }
3309 }
3310
3311 if (xmlDefaultCatalog != NULL)
3312 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3313 return(NULL);
3314}
3315
3316/**
3317 * xmlCatalogGetPublic:
3318 * @pubId: the public ID string
3319 *
3320 * Try to lookup the system ID associated to a public ID
3321 * DEPRECATED, use xmlCatalogResolvePublic()
3322 *
3323 * Returns the system ID if found or NULL otherwise.
3324 */
3325const xmlChar *
3326xmlCatalogGetPublic(const xmlChar *pubID) {
3327 xmlChar *ret;
3328 static xmlChar result[1000];
3329 static int msg = 0;
3330
3331 if (msg == 0) {
3332 xmlGenericError(xmlGenericErrorContext,
3333 "Use of deprecated xmlCatalogGetPublic() call\n");
3334 msg++;
3335 }
3336
3337 if (pubID == NULL)
3338 return(NULL);
3339
3340 if (!xmlCatalogInitialized)
3341 xmlInitializeCatalog();
3342
3343 /*
3344 * Check first the XML catalogs
3345 */
3346 if (xmlDefaultCatalog != NULL) {
3347 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3348 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3349 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3350 result[sizeof(result) - 1] = 0;
3351 return(result);
3352 }
3353 }
3354
3355 if (xmlDefaultCatalog != NULL)
3356 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3357 return(NULL);
3358}
3359
Daniel Veillarda7374592001-05-10 14:17:55 +00003360#endif /* LIBXML_CATALOG_ENABLED */