blob: fca40228f5b85a82f1e3eac1db26031d013bb7be [file] [log] [blame]
Daniel Veillarda7374592001-05-10 14:17:55 +00001/**
2 * catalog.c: set of generic Catalog related routines
3 *
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
6 *
Daniel Veillard344cee72001-08-20 00:08:40 +00007 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
9 *
Daniel Veillarda7374592001-05-10 14:17:55 +000010 * See Copyright for the status of this software.
11 *
12 * Daniel.Veillard@imag.fr
13 */
14
15#include "libxml.h"
16
17#ifdef LIBXML_CATALOG_ENABLED
18#ifdef HAVE_SYS_TYPES_H
19#include <sys/types.h>
20#endif
21#ifdef HAVE_SYS_STAT_H
22#include <sys/stat.h>
23#endif
24#ifdef HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27#ifdef HAVE_FCNTL_H
28#include <fcntl.h>
29#endif
Daniel Veillardc0631a62001-09-20 13:56:06 +000030#ifdef HAVE_STDLIB_H
31#include <stdlib.h>
32#endif
Daniel Veillarda7374592001-05-10 14:17:55 +000033#include <string.h>
34#include <libxml/xmlmemory.h>
35#include <libxml/hash.h>
36#include <libxml/uri.h>
37#include <libxml/parserInternals.h>
38#include <libxml/catalog.h>
39#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000040#include <libxml/threads.h>
Daniel Veillarda7374592001-05-10 14:17:55 +000041
Daniel Veillard6990bf32001-08-23 21:17:48 +000042#define MAX_DELEGATE 50
43
Daniel Veillard344cee72001-08-20 00:08:40 +000044/**
45 * TODO:
46 *
47 * macro to flag unimplemented blocks
48 */
49#define TODO \
50 xmlGenericError(xmlGenericErrorContext, \
51 "Unimplemented block at %s:%d\n", \
52 __FILE__, __LINE__);
53
Daniel Veillardcda96922001-08-21 10:56:31 +000054#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000055#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000056#ifndef XML_XML_DEFAULT_CATALOG
57#define XML_XML_DEFAULT_CATALOG "/etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000058#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000059#ifndef XML_SGML_DEFAULT_CATALOG
60#define XML_SGML_DEFAULT_CATALOG "/etc/sgml/catalog"
61#endif
62
63int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000064
Daniel Veillarda7374592001-05-10 14:17:55 +000065/************************************************************************
66 * *
67 * Types, all private *
68 * *
69 ************************************************************************/
70
71typedef enum {
72 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000073 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000074 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000075 XML_CATA_NEXT_CATALOG,
76 XML_CATA_PUBLIC,
77 XML_CATA_SYSTEM,
78 XML_CATA_REWRITE_SYSTEM,
79 XML_CATA_DELEGATE_PUBLIC,
80 XML_CATA_DELEGATE_SYSTEM,
81 XML_CATA_URI,
82 XML_CATA_REWRITE_URI,
83 XML_CATA_DELEGATE_URI,
84 SGML_CATA_SYSTEM,
85 SGML_CATA_PUBLIC,
86 SGML_CATA_ENTITY,
87 SGML_CATA_PENTITY,
88 SGML_CATA_DOCTYPE,
89 SGML_CATA_LINKTYPE,
90 SGML_CATA_NOTATION,
91 SGML_CATA_DELEGATE,
92 SGML_CATA_BASE,
93 SGML_CATA_CATALOG,
94 SGML_CATA_DOCUMENT,
95 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000096} xmlCatalogEntryType;
97
98typedef struct _xmlCatalogEntry xmlCatalogEntry;
99typedef xmlCatalogEntry *xmlCatalogEntryPtr;
100struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000101 struct _xmlCatalogEntry *next;
102 struct _xmlCatalogEntry *parent;
103 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000104 xmlCatalogEntryType type;
105 xmlChar *name;
106 xmlChar *value;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000107 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000108 int dealloc;
Daniel Veillarda7374592001-05-10 14:17:55 +0000109};
110
Daniel Veillard75b96822001-10-11 18:59:45 +0000111typedef enum {
112 XML_XML_CATALOG_TYPE = 1,
113 XML_SGML_CATALOG_TYPE
114} xmlCatalogType;
115
116#define XML_MAX_SGML_CATA_DEPTH 10
117struct _xmlCatalog {
118 xmlCatalogType type; /* either XML or SGML */
119
120 /*
121 * SGML Catalogs are stored as a simple hash table of catalog entries
122 * Catalog stack to check against overflows when building the
123 * SGML catalog
124 */
125 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
126 int catalNr; /* Number of current catal streams */
127 int catalMax; /* Max number of catal streams */
128 xmlHashTablePtr sgml;
129
130 /*
131 * XML Catalogs are stored as a tree of Catalog entries
132 */
133 xmlCatalogPrefer prefer;
134 xmlCatalogEntryPtr xml;
135};
136
137/************************************************************************
138 * *
139 * Global variables *
140 * *
141 ************************************************************************/
142
Daniel Veillard81463942001-10-16 12:34:39 +0000143/*
144 * Those are preferences
145 */
146static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000147static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000148static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000149
150/*
151 * Hash table containing all the trees of XML catalogs parsed by
152 * the application.
153 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000154static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000155
156/*
157 * The default catalog in use by the application
158 */
159static xmlCatalogPtr xmlDefaultCatalog = NULL;
160
161/*
Daniel Veillard81463942001-10-16 12:34:39 +0000162 * A mutex for modifying the shared global catalog(s)
163 * xmlDefaultCatalog tree.
164 * It also protects xmlCatalogXMLFiles
165 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
166 */
167static xmlRMutexPtr xmlCatalogMutex = NULL;
168
169/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000170 * Whether the catalog support was initialized.
171 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000172static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000173
Daniel Veillarda7374592001-05-10 14:17:55 +0000174
175/************************************************************************
176 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000177 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000178 * *
179 ************************************************************************/
180
Daniel Veillard75b96822001-10-11 18:59:45 +0000181/**
182 * xmlNewCatalogEntry:
183 * @type: type of entry
184 * @name: name of the entry
185 * @value: value of the entry
186 * @prefer: the PUBLIC vs. SYSTEM current preference value
187 *
188 * create a new Catalog entry, this type is shared both by XML and
189 * SGML catalogs, but the acceptable types values differs.
190 *
191 * Returns the xmlCatalogEntryPtr or NULL in case of error
192 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000193static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000194xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000195 const xmlChar *value, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000196 xmlCatalogEntryPtr ret;
197
198 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
199 if (ret == NULL) {
200 xmlGenericError(xmlGenericErrorContext,
201 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
202 return(NULL);
203 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000204 ret->next = NULL;
205 ret->parent = NULL;
206 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000207 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000208 if (name != NULL)
209 ret->name = xmlStrdup(name);
210 else
211 ret->name = NULL;
212 if (value != NULL)
213 ret->value = xmlStrdup(value);
214 else
215 ret->value = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000216 ret->prefer = prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000217 ret->dealloc = 1;
Daniel Veillarda7374592001-05-10 14:17:55 +0000218 return(ret);
219}
220
221static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000222xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
223
Daniel Veillard75b96822001-10-11 18:59:45 +0000224/**
225 * xmlFreeCatalogEntry:
226 * @ret: a Catalog entry
227 *
228 * Free the memory allocated to a Catalog entry
229 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000230static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000231xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
232 if (ret == NULL)
233 return;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000234 if ((ret->children != NULL) && (ret->dealloc == 1))
Daniel Veillard344cee72001-08-20 00:08:40 +0000235 xmlFreeCatalogEntryList(ret->children);
Daniel Veillarda7374592001-05-10 14:17:55 +0000236 if (ret->name != NULL)
237 xmlFree(ret->name);
238 if (ret->value != NULL)
239 xmlFree(ret->value);
240 xmlFree(ret);
241}
242
Daniel Veillard75b96822001-10-11 18:59:45 +0000243/**
244 * xmlFreeCatalogEntryList:
245 * @ret: a Catalog entry list
246 *
247 * Free the memory allocated to a full chained list of Catalog entries
248 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000249static void
250xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
251 xmlCatalogEntryPtr next;
252
253 while (ret != NULL) {
254 next = ret->next;
255 xmlFreeCatalogEntry(ret);
256 ret = next;
257 }
258}
259
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000260/**
Daniel Veillard75b96822001-10-11 18:59:45 +0000261 * xmlNewCatalog:
262 * @type: type of catalog
263 * @prefer: the PUBLIC vs. SYSTEM current preference value
264 *
265 * create a new Catalog, this type is shared both by XML and
266 * SGML catalogs, but the acceptable types values differs.
267 *
268 * Returns the xmlCatalogPtr or NULL in case of error
269 */
270static xmlCatalogPtr
271xmlNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
272 xmlCatalogPtr ret;
273
274 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
275 if (ret == NULL) {
276 xmlGenericError(xmlGenericErrorContext,
277 "malloc of %d byte failed\n", sizeof(xmlCatalog));
278 return(NULL);
279 }
280 memset(ret, 0, sizeof(xmlCatalog));
281 ret->type = type;
282 ret->catalNr = 0;
283 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
284 ret->prefer = prefer;
285 return(ret);
286}
287
288/**
289 * xmlFreeCatalog:
290 * @catal: a Catalog entry
291 *
292 * Free the memory allocated to a Catalog
293 */
294void
295xmlFreeCatalog(xmlCatalogPtr catal) {
296 if (catal == NULL)
297 return;
298 if (catal->xml != NULL)
299 xmlFreeCatalogEntryList(catal->xml);
300 if (catal->sgml != NULL)
301 xmlHashFree(catal->sgml,
302 (xmlHashDeallocator) xmlFreeCatalogEntry);
303 xmlFree(catal);
304}
305
306/************************************************************************
307 * *
308 * Serializing Catalogs *
309 * *
310 ************************************************************************/
311
312/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000313 * xmlCatalogDumpEntry:
314 * @entry: the
315 * @out: the file.
316 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000317 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000318 */
319static void
320xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
321 if ((entry == NULL) || (out == NULL))
322 return;
323 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000324 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000325 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000326 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000327 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000328 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000329 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000330 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000331 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000332 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000333 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000334 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000335 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000336 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000337 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000338 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000339 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000340 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000341 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000342 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000343 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000344 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000345 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000346 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000347 fprintf(out, "SGMLDECL "); break;
348 default:
349 return;
350 }
351 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000352 case SGML_CATA_ENTITY:
353 case SGML_CATA_PENTITY:
354 case SGML_CATA_DOCTYPE:
355 case SGML_CATA_LINKTYPE:
356 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000357 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000358 case SGML_CATA_PUBLIC:
359 case SGML_CATA_SYSTEM:
360 case SGML_CATA_SGMLDECL:
361 case SGML_CATA_DOCUMENT:
362 case SGML_CATA_CATALOG:
363 case SGML_CATA_BASE:
364 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000365 fprintf(out, "\"%s\"", entry->name); break;
366 default:
367 break;
368 }
369 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000370 case SGML_CATA_ENTITY:
371 case SGML_CATA_PENTITY:
372 case SGML_CATA_DOCTYPE:
373 case SGML_CATA_LINKTYPE:
374 case SGML_CATA_NOTATION:
375 case SGML_CATA_PUBLIC:
376 case SGML_CATA_SYSTEM:
377 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000378 fprintf(out, " \"%s\"", entry->value); break;
379 default:
380 break;
381 }
382 fprintf(out, "\n");
383}
384
Daniel Veillard75b96822001-10-11 18:59:45 +0000385static int
386xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
387 int ret;
388 xmlDocPtr doc;
389 xmlNsPtr ns;
390 xmlDtdPtr dtd;
391 xmlNodePtr node, catalog;
392 xmlOutputBufferPtr buf;
393 xmlCatalogEntryPtr cur;
394
395 /*
396 * Rebuild a catalog
397 */
398 doc = xmlNewDoc(NULL);
399 if (doc == NULL)
400 return(-1);
401 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
402 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
403BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
404
405 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
406
407 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
408 if (ns == NULL) {
409 xmlFreeDoc(doc);
410 return(-1);
411 }
412 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
413 if (catalog == NULL) {
414 xmlFreeNs(ns);
415 xmlFreeDoc(doc);
416 return(-1);
417 }
418 catalog->nsDef = ns;
419 xmlAddChild((xmlNodePtr) doc, catalog);
420
421 /*
422 * add all the catalog entries
423 */
424 cur = catal;
425 while (cur != NULL) {
426 switch (cur->type) {
427 case XML_CATA_BROKEN_CATALOG:
428 case XML_CATA_CATALOG:
429 if (cur == catal) {
430 cur = cur->children;
431 continue;
432 }
433 break;
434 case XML_CATA_NEXT_CATALOG:
435 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
436 xmlSetProp(node, BAD_CAST "catalog", cur->value);
437 xmlAddChild(catalog, node);
438 break;
439 case XML_CATA_NONE:
440 break;
441 case XML_CATA_PUBLIC:
442 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
443 xmlSetProp(node, BAD_CAST "publicId", cur->name);
444 xmlSetProp(node, BAD_CAST "uri", cur->value);
445 xmlAddChild(catalog, node);
446 break;
447 case XML_CATA_SYSTEM:
448 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
449 xmlSetProp(node, BAD_CAST "systemId", cur->name);
450 xmlSetProp(node, BAD_CAST "uri", cur->value);
451 xmlAddChild(catalog, node);
452 break;
453 case XML_CATA_REWRITE_SYSTEM:
454 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
455 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
456 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
457 xmlAddChild(catalog, node);
458 break;
459 case XML_CATA_DELEGATE_PUBLIC:
460 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
461 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
462 xmlSetProp(node, BAD_CAST "catalog", cur->value);
463 xmlAddChild(catalog, node);
464 break;
465 case XML_CATA_DELEGATE_SYSTEM:
466 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
467 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
468 xmlSetProp(node, BAD_CAST "catalog", cur->value);
469 xmlAddChild(catalog, node);
470 break;
471 case XML_CATA_URI:
472 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
473 xmlSetProp(node, BAD_CAST "name", cur->name);
474 xmlSetProp(node, BAD_CAST "uri", cur->value);
475 xmlAddChild(catalog, node);
476 break;
477 case XML_CATA_REWRITE_URI:
478 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
479 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
480 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
481 xmlAddChild(catalog, node);
482 break;
483 case XML_CATA_DELEGATE_URI:
484 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
485 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
486 xmlSetProp(node, BAD_CAST "catalog", cur->value);
487 xmlAddChild(catalog, node);
488 break;
489 case SGML_CATA_SYSTEM:
490 case SGML_CATA_PUBLIC:
491 case SGML_CATA_ENTITY:
492 case SGML_CATA_PENTITY:
493 case SGML_CATA_DOCTYPE:
494 case SGML_CATA_LINKTYPE:
495 case SGML_CATA_NOTATION:
496 case SGML_CATA_DELEGATE:
497 case SGML_CATA_BASE:
498 case SGML_CATA_CATALOG:
499 case SGML_CATA_DOCUMENT:
500 case SGML_CATA_SGMLDECL:
501 break;
502 }
503 cur = cur->next;
504 }
505
506 /*
507 * reserialize it
508 */
509 buf = xmlOutputBufferCreateFile(out, NULL);
510 if (buf == NULL) {
511 xmlFreeDoc(doc);
512 return(-1);
513 }
514 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
515
516 /*
517 * Free it
518 */
519 xmlFreeDoc(doc);
520
521 return(ret);
522}
523
524/************************************************************************
525 * *
526 * Converting SGML Catalogs to XML *
527 * *
528 ************************************************************************/
529
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000530/**
531 * xmlCatalogConvertEntry:
532 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000533 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000534 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000535 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000536 */
537static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000538xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
539 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
540 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000541 return;
542 switch (entry->type) {
543 case SGML_CATA_ENTITY:
544 entry->type = XML_CATA_PUBLIC;
545 break;
546 case SGML_CATA_PENTITY:
547 entry->type = XML_CATA_PUBLIC;
548 break;
549 case SGML_CATA_DOCTYPE:
550 entry->type = XML_CATA_PUBLIC;
551 break;
552 case SGML_CATA_LINKTYPE:
553 entry->type = XML_CATA_PUBLIC;
554 break;
555 case SGML_CATA_NOTATION:
556 entry->type = XML_CATA_PUBLIC;
557 break;
558 case SGML_CATA_PUBLIC:
559 entry->type = XML_CATA_PUBLIC;
560 break;
561 case SGML_CATA_SYSTEM:
562 entry->type = XML_CATA_SYSTEM;
563 break;
564 case SGML_CATA_DELEGATE:
565 entry->type = XML_CATA_DELEGATE_PUBLIC;
566 break;
567 case SGML_CATA_CATALOG:
568 entry->type = XML_CATA_CATALOG;
569 break;
570 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000571 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000572 (xmlHashDeallocator) xmlFreeCatalogEntry);
573 return;
574 }
575 /*
576 * Conversion successful, remove from the SGML catalog
577 * and add it to the default XML one
578 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000579 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
580 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000581 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000582 if (catal->xml->children == NULL)
583 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000584 else {
585 xmlCatalogEntryPtr prev;
586
Daniel Veillard75b96822001-10-11 18:59:45 +0000587 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000588 while (prev->next != NULL)
589 prev = prev->next;
590 prev->next = entry;
591 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000592}
593
594/**
595 * xmlConvertSGMLCatalog:
596 * @catal: the catalog
597 *
598 * Convert all the SGML catalog entries as XML ones
599 *
600 * Returns the number of entries converted if successful, -1 otherwise
601 */
602int
603xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
604
605 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
606 return(-1);
607
608 if (xmlDebugCatalogs) {
609 xmlGenericError(xmlGenericErrorContext,
610 "Converting SGML catalog to XML\n");
611 }
612 xmlHashScan(catal->sgml,
613 (xmlHashScanner) xmlCatalogConvertEntry,
614 &catal);
615 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000616}
617
Daniel Veillarda7374592001-05-10 14:17:55 +0000618/************************************************************************
619 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000620 * Helper function *
621 * *
622 ************************************************************************/
623
624/**
625 * xmlCatalogUnWrapURN:
626 * @urn: an "urn:publicid:" to unwrapp
627 *
628 * Expand the URN into the equivalent Public Identifier
629 *
630 * Returns the new identifier or NULL, the string must be deallocated
631 * by the caller.
632 */
633static xmlChar *
634xmlCatalogUnWrapURN(const xmlChar *urn) {
635 xmlChar result[2000];
636 unsigned int i = 0;
637
638 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
639 return(NULL);
640 urn += sizeof(XML_URN_PUBID) - 1;
641
642 while (*urn != 0) {
643 if (i > sizeof(result) - 3)
644 break;
645 if (*urn == '+') {
646 result[i++] = ' ';
647 urn++;
648 } else if (*urn == ':') {
649 result[i++] = '/';
650 result[i++] = '/';
651 urn++;
652 } else if (*urn == ';') {
653 result[i++] = ':';
654 result[i++] = ':';
655 urn++;
656 } else if (*urn == '%') {
657 if ((urn[1] == '2') && (urn[1] == 'B'))
658 result[i++] = '+';
659 else if ((urn[1] == '3') && (urn[1] == 'A'))
660 result[i++] = ':';
661 else if ((urn[1] == '2') && (urn[1] == 'F'))
662 result[i++] = '/';
663 else if ((urn[1] == '3') && (urn[1] == 'B'))
664 result[i++] = ';';
665 else if ((urn[1] == '2') && (urn[1] == '7'))
666 result[i++] = '\'';
667 else if ((urn[1] == '3') && (urn[1] == 'F'))
668 result[i++] = '?';
669 else if ((urn[1] == '2') && (urn[1] == '3'))
670 result[i++] = '#';
671 else if ((urn[1] == '2') && (urn[1] == '5'))
672 result[i++] = '%';
673 else {
674 result[i++] = *urn;
675 urn++;
676 continue;
677 }
678 urn += 3;
679 } else {
680 result[i++] = *urn;
681 urn++;
682 }
683 }
684 result[i] = 0;
685
686 return(xmlStrdup(result));
687}
688
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000689/**
690 * xmlParseCatalogFile:
691 * @filename: the filename
692 *
693 * parse an XML file and build a tree. It's like xmlParseFile()
694 * except it bypass all catalog lookups.
695 *
696 * Returns the resulting document tree or NULL in case of error
697 */
698
699xmlDocPtr
700xmlParseCatalogFile(const char *filename) {
701 xmlDocPtr ret;
702 xmlParserCtxtPtr ctxt;
703 char *directory = NULL;
704 xmlParserInputPtr inputStream;
705 xmlParserInputBufferPtr buf;
706
707 ctxt = xmlNewParserCtxt();
708 if (ctxt == NULL) {
709 if (xmlDefaultSAXHandler.error != NULL) {
710 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
711 }
712 return(NULL);
713 }
714
715 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
716 if (buf == NULL) {
717 xmlFreeParserCtxt(ctxt);
718 return(NULL);
719 }
720
721 inputStream = xmlNewInputStream(ctxt);
722 if (inputStream == NULL) {
723 xmlFreeParserCtxt(ctxt);
724 return(NULL);
725 }
726
727 inputStream->filename = xmlMemStrdup(filename);
728 inputStream->buf = buf;
729 inputStream->base = inputStream->buf->buffer->content;
730 inputStream->cur = inputStream->buf->buffer->content;
731 inputStream->end =
732 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
733
734 inputPush(ctxt, inputStream);
735 if ((ctxt->directory == NULL) && (directory == NULL))
736 directory = xmlParserGetDirectory(filename);
737 if ((ctxt->directory == NULL) && (directory != NULL))
738 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000739 ctxt->valid = 0;
740 ctxt->validate = 0;
741 ctxt->loadsubset = 0;
742 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000743
744 xmlParseDocument(ctxt);
745
746 if (ctxt->wellFormed)
747 ret = ctxt->myDoc;
748 else {
749 ret = NULL;
750 xmlFreeDoc(ctxt->myDoc);
751 ctxt->myDoc = NULL;
752 }
753 xmlFreeParserCtxt(ctxt);
754
755 return(ret);
756}
757
Daniel Veillard75b96822001-10-11 18:59:45 +0000758/**
759 * xmlLoadFileContent:
760 * @filename: a file path
761 *
762 * Load a file content into memory.
763 *
764 * Returns a pointer to the 0 terminated string or NULL in case of error
765 */
766static xmlChar *
767xmlLoadFileContent(const char *filename)
768{
769#ifdef HAVE_STAT
770 int fd;
771#else
772 FILE *fd;
773#endif
774 int len;
775 long size;
776
777#ifdef HAVE_STAT
778 struct stat info;
779#endif
780 xmlChar *content;
781
782 if (filename == NULL)
783 return (NULL);
784
785#ifdef HAVE_STAT
786 if (stat(filename, &info) < 0)
787 return (NULL);
788#endif
789
790#ifdef HAVE_STAT
791 if ((fd = open(filename, O_RDONLY)) < 0) {
792#else
793 if ((fd = fopen(filename, "rb")) == NULL) {
794#endif
795 return (NULL);
796 }
797#ifdef HAVE_STAT
798 size = info.st_size;
799#else
800 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
801 fclose(fd);
802 return (NULL);
803 }
804#endif
805 content = xmlMalloc(size + 10);
806 if (content == NULL) {
807 xmlGenericError(xmlGenericErrorContext,
808 "malloc of %d byte failed\n", size + 10);
809 return (NULL);
810 }
811#ifdef HAVE_STAT
812 len = read(fd, content, size);
813#else
814 len = fread(content, 1, size, fd);
815#endif
816 if (len < 0) {
817 xmlFree(content);
818 return (NULL);
819 }
820#ifdef HAVE_STAT
821 close(fd);
822#else
823 fclose(fd);
824#endif
825 content[len] = 0;
826
827 return(content);
828}
829
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000830/************************************************************************
831 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000832 * The XML Catalog parser *
833 * *
834 ************************************************************************/
835
836static xmlCatalogEntryPtr
837xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000838static xmlCatalogEntryPtr
839xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
840 const char *file);
841static void
842xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
843 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000844static xmlChar *
845xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
846 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000847static xmlChar *
848xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
849
Daniel Veillard344cee72001-08-20 00:08:40 +0000850
Daniel Veillard75b96822001-10-11 18:59:45 +0000851/**
852 * xmlGetXMLCatalogEntryType:
853 * @name: the name
854 *
855 * lookup the internal type associated to an XML catalog entry name
856 *
857 * Returns the type associate with that name
858 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000859static xmlCatalogEntryType
860xmlGetXMLCatalogEntryType(const xmlChar *name) {
861 xmlCatalogEntryType type = XML_CATA_NONE;
862 if (xmlStrEqual(name, (const xmlChar *) "system"))
863 type = XML_CATA_SYSTEM;
864 else if (xmlStrEqual(name, (const xmlChar *) "public"))
865 type = XML_CATA_PUBLIC;
866 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
867 type = XML_CATA_REWRITE_SYSTEM;
868 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
869 type = XML_CATA_DELEGATE_PUBLIC;
870 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
871 type = XML_CATA_DELEGATE_SYSTEM;
872 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
873 type = XML_CATA_URI;
874 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
875 type = XML_CATA_REWRITE_URI;
876 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
877 type = XML_CATA_DELEGATE_URI;
878 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
879 type = XML_CATA_NEXT_CATALOG;
880 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
881 type = XML_CATA_CATALOG;
882 return(type);
883}
884
Daniel Veillard75b96822001-10-11 18:59:45 +0000885/**
886 * xmlParseXMLCatalogOneNode:
887 * @cur: the XML node
888 * @type: the type of Catalog entry
889 * @name: the name of the node
890 * @attrName: the attribute holding the value
891 * @uriAttrName: the attribute holding the URI-Reference
892 * @prefer: the PUBLIC vs. SYSTEM current preference value
893 *
894 * Finishes the examination of an XML tree node of a catalog and build
895 * a Catalog entry from it.
896 *
897 * Returns the new Catalog entry node or NULL in case of error.
898 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000899static xmlCatalogEntryPtr
900xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
901 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000902 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000903 int ok = 1;
904 xmlChar *uriValue;
905 xmlChar *nameValue = NULL;
906 xmlChar *base = NULL;
907 xmlChar *URL = NULL;
908 xmlCatalogEntryPtr ret = NULL;
909
910 if (attrName != NULL) {
911 nameValue = xmlGetProp(cur, attrName);
912 if (nameValue == NULL) {
913 xmlGenericError(xmlGenericErrorContext,
914 "%s entry lacks '%s'\n", name, attrName);
915 ok = 0;
916 }
917 }
918 uriValue = xmlGetProp(cur, uriAttrName);
919 if (uriValue == NULL) {
920 xmlGenericError(xmlGenericErrorContext,
921 "%s entry lacks '%s'\n", name, uriAttrName);
922 ok = 0;
923 }
924 if (!ok) {
925 if (nameValue != NULL)
926 xmlFree(nameValue);
927 if (uriValue != NULL)
928 xmlFree(uriValue);
929 return(NULL);
930 }
931
932 base = xmlNodeGetBase(cur->doc, cur);
933 URL = xmlBuildURI(uriValue, base);
934 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000935 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000936 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000937 xmlGenericError(xmlGenericErrorContext,
938 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000939 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000940 xmlGenericError(xmlGenericErrorContext,
941 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000942 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000943 ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000944 } else {
945 xmlGenericError(xmlGenericErrorContext,
946 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
947 }
948 if (nameValue != NULL)
949 xmlFree(nameValue);
950 if (uriValue != NULL)
951 xmlFree(uriValue);
952 if (base != NULL)
953 xmlFree(base);
954 if (URL != NULL)
955 xmlFree(URL);
956 return(ret);
957}
958
Daniel Veillard75b96822001-10-11 18:59:45 +0000959/**
960 * xmlParseXMLCatalogNode:
961 * @cur: the XML node
962 * @prefer: the PUBLIC vs. SYSTEM current preference value
963 * @parent: the parent Catalog entry
964 *
965 * Examines an XML tree node of a catalog and build
966 * a Catalog entry from it adding it to its parent. The examination can
967 * be recursive.
968 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000969static void
970xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
971 xmlCatalogEntryPtr parent)
972{
973 xmlChar *uri = NULL;
974 xmlChar *URL = NULL;
975 xmlChar *base = NULL;
976 xmlCatalogEntryPtr entry = NULL;
977
978 if (cur == NULL)
979 return;
980 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
981 xmlChar *prop;
982
983 prop = xmlGetProp(cur, BAD_CAST "prefer");
984 if (prop != NULL) {
985 if (xmlStrEqual(prop, BAD_CAST "system")) {
986 prefer = XML_CATA_PREFER_SYSTEM;
987 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
988 prefer = XML_CATA_PREFER_PUBLIC;
989 } else {
990 xmlGenericError(xmlGenericErrorContext,
991 "Invalid value for prefer: '%s'\n", prop);
992 }
993 xmlFree(prop);
994 }
995 /*
996 * Recurse to propagate prefer to the subtree
997 * (xml:base handling is automated)
998 */
999 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1000 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1001 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001002 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001003 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1004 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001005 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001006 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1007 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1008 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001009 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001010 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1011 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1012 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001013 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001014 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1015 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1016 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001017 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001018 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1019 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1020 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001021 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001022 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1023 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1024 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001025 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001026 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1027 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1028 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001029 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001030 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1031 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1032 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001033 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001034 }
1035 if ((entry != NULL) && (parent != NULL)) {
1036 entry->parent = parent;
1037 if (parent->children == NULL)
1038 parent->children = entry;
1039 else {
1040 xmlCatalogEntryPtr prev;
1041
1042 prev = parent->children;
1043 while (prev->next != NULL)
1044 prev = prev->next;
1045 prev->next = entry;
1046 }
1047 }
1048 if (base != NULL)
1049 xmlFree(base);
1050 if (uri != NULL)
1051 xmlFree(uri);
1052 if (URL != NULL)
1053 xmlFree(URL);
1054}
1055
Daniel Veillard75b96822001-10-11 18:59:45 +00001056/**
1057 * xmlParseXMLCatalogNodeList:
1058 * @cur: the XML node list of siblings
1059 * @prefer: the PUBLIC vs. SYSTEM current preference value
1060 * @parent: the parent Catalog entry
1061 *
1062 * Examines a list of XML sibling nodes of a catalog and build
1063 * a list of Catalog entry from it adding it to the parent.
1064 * The examination will recurse to examine node subtrees.
1065 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001066static void
1067xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1068 xmlCatalogEntryPtr parent) {
1069 while (cur != NULL) {
1070 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1071 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1072 xmlParseXMLCatalogNode(cur, prefer, parent);
1073 }
1074 cur = cur->next;
1075 }
1076 /* TODO: sort the list according to REWRITE lengths and prefer value */
1077}
1078
Daniel Veillard75b96822001-10-11 18:59:45 +00001079/**
1080 * xmlParseXMLCatalog:
1081 * @value: the content in-memory of the catalog serialization
1082 * @prefer: the PUBLIC vs. SYSTEM current preference value
1083 * @file: the filename for the catalog
1084 *
1085 * Parses the catalog content to extract the XML tree and then analyze the
1086 * tree to build a list of Catalog entries corresponding to this catalog
1087 *
1088 * Returns the resulting Catalog entries list
1089 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001090static xmlCatalogEntryPtr
1091xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
1092 const char *file) {
1093 xmlDocPtr doc;
1094 xmlNodePtr cur;
1095 xmlChar *prop;
1096 xmlCatalogEntryPtr parent = NULL;
1097
1098 if ((value == NULL) || (file == NULL))
1099 return(NULL);
1100
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001101 if (xmlDebugCatalogs)
1102 xmlGenericError(xmlGenericErrorContext,
1103 "Parsing catalog %s's content\n", file);
1104
Daniel Veillard344cee72001-08-20 00:08:40 +00001105 doc = xmlParseDoc((xmlChar *) value);
1106 if (doc == NULL)
1107 return(NULL);
1108 doc->URL = xmlStrdup((const xmlChar *) file);
1109
1110 cur = xmlDocGetRootElement(doc);
1111 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1112 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1113 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1114
Daniel Veillard344cee72001-08-20 00:08:40 +00001115 prop = xmlGetProp(cur, BAD_CAST "prefer");
1116 if (prop != NULL) {
1117 if (xmlStrEqual(prop, BAD_CAST "system")) {
1118 prefer = XML_CATA_PREFER_SYSTEM;
1119 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1120 prefer = XML_CATA_PREFER_PUBLIC;
1121 } else {
1122 xmlGenericError(xmlGenericErrorContext,
1123 "Invalid value for prefer: '%s'\n",
1124 prop);
1125 }
1126 xmlFree(prop);
1127 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001128 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1129 (const xmlChar *)file, prefer);
1130 if (parent == NULL) {
1131 xmlFreeDoc(doc);
1132 return(NULL);
1133 }
1134
Daniel Veillard344cee72001-08-20 00:08:40 +00001135 cur = cur->children;
1136 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1137 } else {
1138 xmlGenericError(xmlGenericErrorContext,
1139 "File %s is not an XML Catalog\n", file);
1140 xmlFreeDoc(doc);
1141 return(NULL);
1142 }
1143 xmlFreeDoc(doc);
1144 return(parent);
1145}
1146
Daniel Veillard75b96822001-10-11 18:59:45 +00001147/**
1148 * xmlParseXMLCatalogFile:
1149 * @prefer: the PUBLIC vs. SYSTEM current preference value
1150 * @filename: the filename for the catalog
1151 *
1152 * Parses the catalog file to extract the XML tree and then analyze the
1153 * tree to build a list of Catalog entries corresponding to this catalog
1154 *
1155 * Returns the resulting Catalog entries list
1156 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001157static xmlCatalogEntryPtr
1158xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1159 xmlDocPtr doc;
1160 xmlNodePtr cur;
1161 xmlChar *prop;
1162 xmlCatalogEntryPtr parent = NULL;
1163
1164 if (filename == NULL)
1165 return(NULL);
1166
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001167 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001168 if (doc == NULL) {
1169 if (xmlDebugCatalogs)
1170 xmlGenericError(xmlGenericErrorContext,
1171 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001172 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001173 }
1174
1175 if (xmlDebugCatalogs)
1176 xmlGenericError(xmlGenericErrorContext,
1177 "Parsing catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001178
1179 cur = xmlDocGetRootElement(doc);
1180 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1181 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1182 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1183
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001184 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1185 (const xmlChar *)filename, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001186 if (parent == NULL) {
1187 xmlFreeDoc(doc);
1188 return(NULL);
1189 }
1190
1191 prop = xmlGetProp(cur, BAD_CAST "prefer");
1192 if (prop != NULL) {
1193 if (xmlStrEqual(prop, BAD_CAST "system")) {
1194 prefer = XML_CATA_PREFER_SYSTEM;
1195 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1196 prefer = XML_CATA_PREFER_PUBLIC;
1197 } else {
1198 xmlGenericError(xmlGenericErrorContext,
1199 "Invalid value for prefer: '%s'\n",
1200 prop);
1201 }
1202 xmlFree(prop);
1203 }
1204 cur = cur->children;
1205 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1206 } else {
1207 xmlGenericError(xmlGenericErrorContext,
1208 "File %s is not an XML Catalog\n", filename);
1209 xmlFreeDoc(doc);
1210 return(NULL);
1211 }
1212 xmlFreeDoc(doc);
1213 return(parent);
1214}
1215
Daniel Veillardcda96922001-08-21 10:56:31 +00001216/**
1217 * xmlFetchXMLCatalogFile:
1218 * @catal: an existing but incomplete catalog entry
1219 *
1220 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001221 *
1222 * Returns 0 in case of success, -1 otherwise
1223 */
1224static int
1225xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001226 xmlCatalogEntryPtr children = NULL, doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001227
1228 if (catal == NULL)
1229 return(-1);
1230 if (catal->value == NULL)
1231 return(-1);
1232 if (catal->children != NULL)
1233 return(-1);
1234
Daniel Veillard81463942001-10-16 12:34:39 +00001235 /*
1236 * lock the whole catalog for modification
1237 */
1238 xmlRMutexLock(xmlCatalogMutex);
1239 if (catal->children != NULL) {
1240 /* Okay someone else did it in the meantime */
1241 xmlRMutexUnlock(xmlCatalogMutex);
1242 return(0);
1243
1244
1245 }
1246
Daniel Veillard6990bf32001-08-23 21:17:48 +00001247 if (xmlCatalogXMLFiles != NULL)
1248 children = (xmlCatalogEntryPtr)
1249 xmlHashLookup(xmlCatalogXMLFiles, catal->value);
1250 if (children != NULL) {
1251 catal->children = children;
1252 catal->dealloc = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00001253 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001254 return(0);
1255 }
1256
Daniel Veillardcda96922001-08-21 10:56:31 +00001257 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001258 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1259 * use the existing catalog, there is no recusivity allowed at
1260 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001261 */
Daniel Veillard6990bf32001-08-23 21:17:48 +00001262 doc = xmlParseXMLCatalogFile(catal->prefer, catal->value);
1263 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001264 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001265 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001266 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001267 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00001268 if ((catal->type == XML_CATA_CATALOG) &&
1269 (doc->type == XML_CATA_CATALOG)) {
1270 children = doc->children;
1271 doc->children = NULL;
1272 xmlFreeCatalogEntryList(doc);
1273 } else {
1274 children = doc;
1275 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001276
Daniel Veillard81463942001-10-16 12:34:39 +00001277 catal->children = children;
1278 catal->dealloc = 1;
1279 if (xmlCatalogXMLFiles == NULL)
1280 xmlCatalogXMLFiles = xmlHashCreate(10);
1281 if (xmlCatalogXMLFiles != NULL) {
1282 if (children != NULL)
1283 xmlHashAddEntry(xmlCatalogXMLFiles, catal->value, children);
Daniel Veillardcda96922001-08-21 10:56:31 +00001284 }
Daniel Veillard81463942001-10-16 12:34:39 +00001285 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001286 return(0);
1287}
1288
Daniel Veillard75b96822001-10-11 18:59:45 +00001289/************************************************************************
1290 * *
1291 * XML Catalog handling *
1292 * *
1293 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001294
1295/**
1296 * xmlAddXMLCatalog:
1297 * @catal: top of an XML catalog
1298 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001299 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001300 * @replace: the replacement value for the match
1301 *
1302 * Add an entry in the XML catalog, it may overwrite existing but
1303 * different entries.
1304 *
1305 * Returns 0 if successful, -1 otherwise
1306 */
1307static int
1308xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1309 const xmlChar *orig, const xmlChar *replace) {
1310 xmlCatalogEntryPtr cur;
1311 xmlCatalogEntryType typ;
1312
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001313 if ((catal == NULL) ||
1314 ((catal->type != XML_CATA_CATALOG) &&
1315 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001316 return(-1);
1317 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001318 if (typ == XML_CATA_NONE) {
1319 if (xmlDebugCatalogs)
1320 xmlGenericError(xmlGenericErrorContext,
1321 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001322 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001323 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001324
1325 cur = catal->children;
1326 /*
1327 * Might be a simple "update in place"
1328 */
1329 if (cur != NULL) {
1330 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001331 if ((orig != NULL) && (cur->type == typ) &&
1332 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001333 if (xmlDebugCatalogs)
1334 xmlGenericError(xmlGenericErrorContext,
1335 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001336 if (cur->value != NULL)
1337 xmlFree(cur->value);
1338 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001339 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001340 }
1341 if (cur->next == NULL)
1342 break;
1343 cur = cur->next;
1344 }
1345 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001346 if (xmlDebugCatalogs)
1347 xmlGenericError(xmlGenericErrorContext,
1348 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001349 if (cur == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001350 catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001351 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001352 cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillardcda96922001-08-21 10:56:31 +00001353 return(0);
1354}
1355
1356/**
1357 * xmlDelXMLCatalog:
1358 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001359 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001360 *
1361 * Remove entries in the XML catalog where the value or the URI
1362 * is equal to @value
1363 *
1364 * Returns the number of entries removed if successful, -1 otherwise
1365 */
1366static int
1367xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1368 xmlCatalogEntryPtr cur, prev, tmp;
1369 int ret = 0;
1370
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001371 if ((catal == NULL) ||
1372 ((catal->type != XML_CATA_CATALOG) &&
1373 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001374 return(-1);
1375 if (value == NULL)
1376 return(-1);
1377
1378 /*
1379 * Scan the children
1380 */
1381 cur = catal->children;
1382 prev = NULL;
1383 while (cur != NULL) {
1384 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1385 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001386 if (xmlDebugCatalogs) {
1387 if (cur->name != NULL)
1388 xmlGenericError(xmlGenericErrorContext,
1389 "Removing element %s from catalog\n", cur->name);
1390 else
1391 xmlGenericError(xmlGenericErrorContext,
1392 "Removing element %s from catalog\n", cur->value);
1393 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001394 ret++;
1395 tmp = cur;
1396 cur = tmp->next;
1397 if (prev == NULL) {
1398 catal->children = cur;
1399 } else {
1400 prev->next = cur;
1401 }
1402 xmlFreeCatalogEntry(tmp);
1403 continue;
1404 }
1405 prev = cur;
1406 cur = cur->next;
1407 }
1408 return(ret);
1409}
1410
1411/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001412 * xmlCatalogXMLResolve:
1413 * @catal: a catalog list
1414 * @pubId: the public ID string
1415 * @sysId: the system ID string
1416 *
1417 * Do a complete resolution lookup of an External Identifier for a
1418 * list of catalog entries.
1419 *
1420 * Implements (or tries to) 7.1. External Identifier Resolution
1421 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1422 *
1423 * Returns the URI of the resource or NULL if not found
1424 */
1425static xmlChar *
1426xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1427 const xmlChar *sysID) {
1428 xmlChar *ret = NULL;
1429 xmlCatalogEntryPtr cur;
1430 int haveDelegate = 0;
1431 int haveNext = 0;
1432
1433 /*
1434 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1435 */
1436 if (sysID != NULL) {
1437 xmlCatalogEntryPtr rewrite = NULL;
1438 int lenrewrite = 0, len;
1439 cur = catal;
1440 haveDelegate = 0;
1441 while (cur != NULL) {
1442 switch (cur->type) {
1443 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001444 if (xmlStrEqual(sysID, cur->name)) {
1445 if (xmlDebugCatalogs)
1446 xmlGenericError(xmlGenericErrorContext,
1447 "Found system match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001448 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001449 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001450 break;
1451 case XML_CATA_REWRITE_SYSTEM:
1452 len = xmlStrlen(cur->name);
1453 if ((len > lenrewrite) &&
1454 (!xmlStrncmp(sysID, cur->name, len))) {
1455 lenrewrite = len;
1456 rewrite = cur;
1457 }
1458 break;
1459 case XML_CATA_DELEGATE_SYSTEM:
1460 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1461 haveDelegate++;
1462 break;
1463 case XML_CATA_NEXT_CATALOG:
1464 haveNext++;
1465 break;
1466 default:
1467 break;
1468 }
1469 cur = cur->next;
1470 }
1471 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001472 if (xmlDebugCatalogs)
1473 xmlGenericError(xmlGenericErrorContext,
1474 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001475 ret = xmlStrdup(rewrite->value);
1476 if (ret != NULL)
1477 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1478 return(ret);
1479 }
1480 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001481 const xmlChar *delegates[MAX_DELEGATE];
1482 int nbList = 0, i;
1483
Daniel Veillardcda96922001-08-21 10:56:31 +00001484 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001485 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001486 * matches when the list was produced.
1487 */
1488 cur = catal;
1489 while (cur != NULL) {
1490 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1491 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001492 for (i = 0;i < nbList;i++)
1493 if (xmlStrEqual(cur->value, delegates[i]))
1494 break;
1495 if (i < nbList) {
1496 cur = cur->next;
1497 continue;
1498 }
1499 if (nbList < MAX_DELEGATE)
1500 delegates[nbList++] = cur->value;
1501
Daniel Veillardcda96922001-08-21 10:56:31 +00001502 if (cur->children == NULL) {
1503 xmlFetchXMLCatalogFile(cur);
1504 }
1505 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001506 if (xmlDebugCatalogs)
1507 xmlGenericError(xmlGenericErrorContext,
1508 "Trying system delegate %s\n", cur->value);
1509 ret = xmlCatalogListXMLResolve(cur->children, NULL,
1510 sysID);
1511 if (ret != NULL)
1512 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001513 }
1514 }
1515 cur = cur->next;
1516 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001517 /*
1518 * Apply the cut algorithm explained in 4/
1519 */
1520 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001521 }
1522 }
1523 /*
1524 * Then tries 5/ 6/ if a public ID is provided
1525 */
1526 if (pubID != NULL) {
1527 cur = catal;
1528 haveDelegate = 0;
1529 while (cur != NULL) {
1530 switch (cur->type) {
1531 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001532 if (xmlStrEqual(pubID, cur->name)) {
1533 if (xmlDebugCatalogs)
1534 xmlGenericError(xmlGenericErrorContext,
1535 "Found public match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001536 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001537 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001538 break;
1539 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001540 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1541 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001542 haveDelegate++;
1543 break;
1544 case XML_CATA_NEXT_CATALOG:
1545 if (sysID == NULL)
1546 haveNext++;
1547 break;
1548 default:
1549 break;
1550 }
1551 cur = cur->next;
1552 }
1553 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001554 const xmlChar *delegates[MAX_DELEGATE];
1555 int nbList = 0, i;
1556
Daniel Veillardcda96922001-08-21 10:56:31 +00001557 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001558 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001559 * matches when the list was produced.
1560 */
1561 cur = catal;
1562 while (cur != NULL) {
1563 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001564 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1565 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001566
1567 for (i = 0;i < nbList;i++)
1568 if (xmlStrEqual(cur->value, delegates[i]))
1569 break;
1570 if (i < nbList) {
1571 cur = cur->next;
1572 continue;
1573 }
1574 if (nbList < MAX_DELEGATE)
1575 delegates[nbList++] = cur->value;
1576
Daniel Veillardcda96922001-08-21 10:56:31 +00001577 if (cur->children == NULL) {
1578 xmlFetchXMLCatalogFile(cur);
1579 }
1580 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001581 if (xmlDebugCatalogs)
1582 xmlGenericError(xmlGenericErrorContext,
1583 "Trying public delegate %s\n", cur->value);
1584 ret = xmlCatalogListXMLResolve(cur->children, pubID,
1585 NULL);
1586 if (ret != NULL)
1587 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001588 }
1589 }
1590 cur = cur->next;
1591 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001592 /*
1593 * Apply the cut algorithm explained in 4/
1594 */
1595 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001596 }
1597 }
1598 if (haveNext) {
1599 cur = catal;
1600 while (cur != NULL) {
1601 if (cur->type == XML_CATA_NEXT_CATALOG) {
1602 if (cur->children == NULL) {
1603 xmlFetchXMLCatalogFile(cur);
1604 }
1605 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001606 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1607 if (ret != NULL)
1608 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001609 }
1610 }
1611 cur = cur->next;
1612 }
1613 }
1614
1615 return(NULL);
1616}
1617
1618/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001619 * xmlCatalogXMLResolveURI:
1620 * @catal: a catalog list
1621 * @URI: the URI
1622 * @sysId: the system ID string
1623 *
1624 * Do a complete resolution lookup of an External Identifier for a
1625 * list of catalog entries.
1626 *
1627 * Implements (or tries to) 7.2.2. URI Resolution
1628 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1629 *
1630 * Returns the URI of the resource or NULL if not found
1631 */
1632static xmlChar *
1633xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1634 xmlChar *ret = NULL;
1635 xmlCatalogEntryPtr cur;
1636 int haveDelegate = 0;
1637 int haveNext = 0;
1638 xmlCatalogEntryPtr rewrite = NULL;
1639 int lenrewrite = 0, len;
1640
1641 if (catal == NULL)
1642 return(NULL);
1643
1644 if (URI == NULL)
1645 return(NULL);
1646
1647 /*
1648 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1649 */
1650 cur = catal;
1651 haveDelegate = 0;
1652 while (cur != NULL) {
1653 switch (cur->type) {
1654 case XML_CATA_URI:
1655 if (xmlStrEqual(URI, cur->name)) {
1656 if (xmlDebugCatalogs)
1657 xmlGenericError(xmlGenericErrorContext,
1658 "Found URI match %s\n", cur->name);
1659 return(xmlStrdup(cur->value));
1660 }
1661 break;
1662 case XML_CATA_REWRITE_URI:
1663 len = xmlStrlen(cur->name);
1664 if ((len > lenrewrite) &&
1665 (!xmlStrncmp(URI, cur->name, len))) {
1666 lenrewrite = len;
1667 rewrite = cur;
1668 }
1669 break;
1670 case XML_CATA_DELEGATE_URI:
1671 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1672 haveDelegate++;
1673 break;
1674 case XML_CATA_NEXT_CATALOG:
1675 haveNext++;
1676 break;
1677 default:
1678 break;
1679 }
1680 cur = cur->next;
1681 }
1682 if (rewrite != NULL) {
1683 if (xmlDebugCatalogs)
1684 xmlGenericError(xmlGenericErrorContext,
1685 "Using rewriting rule %s\n", rewrite->name);
1686 ret = xmlStrdup(rewrite->value);
1687 if (ret != NULL)
1688 ret = xmlStrcat(ret, &URI[lenrewrite]);
1689 return(ret);
1690 }
1691 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001692 const xmlChar *delegates[MAX_DELEGATE];
1693 int nbList = 0, i;
1694
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001695 /*
1696 * Assume the entries have been sorted by decreasing substring
1697 * matches when the list was produced.
1698 */
1699 cur = catal;
1700 while (cur != NULL) {
1701 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1702 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001703 for (i = 0;i < nbList;i++)
1704 if (xmlStrEqual(cur->value, delegates[i]))
1705 break;
1706 if (i < nbList) {
1707 cur = cur->next;
1708 continue;
1709 }
1710 if (nbList < MAX_DELEGATE)
1711 delegates[nbList++] = cur->value;
1712
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001713 if (cur->children == NULL) {
1714 xmlFetchXMLCatalogFile(cur);
1715 }
1716 if (cur->children != NULL) {
1717 if (xmlDebugCatalogs)
1718 xmlGenericError(xmlGenericErrorContext,
1719 "Trying URI delegate %s\n", cur->value);
1720 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1721 if (ret != NULL)
1722 return(ret);
1723 }
1724 }
1725 cur = cur->next;
1726 }
1727 /*
1728 * Apply the cut algorithm explained in 4/
1729 */
1730 return(XML_CATAL_BREAK);
1731 }
1732 if (haveNext) {
1733 cur = catal;
1734 while (cur != NULL) {
1735 if (cur->type == XML_CATA_NEXT_CATALOG) {
1736 if (cur->children == NULL) {
1737 xmlFetchXMLCatalogFile(cur);
1738 }
1739 if (cur->children != NULL) {
1740 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1741 if (ret != NULL)
1742 return(ret);
1743 }
1744 }
1745 cur = cur->next;
1746 }
1747 }
1748
1749 return(NULL);
1750}
1751
1752/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001753 * xmlCatalogListXMLResolve:
1754 * @catal: a catalog list
1755 * @pubId: the public ID string
1756 * @sysId: the system ID string
1757 *
1758 * Do a complete resolution lookup of an External Identifier for a
1759 * list of catalogs
1760 *
1761 * Implements (or tries to) 7.1. External Identifier Resolution
1762 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1763 *
1764 * Returns the URI of the resource or NULL if not found
1765 */
1766static xmlChar *
1767xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1768 const xmlChar *sysID) {
1769 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001770 xmlChar *urnID = NULL;
1771
1772 if (catal == NULL)
1773 return(NULL);
1774 if ((pubID == NULL) && (sysID == NULL))
1775 return(NULL);
1776
1777 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1778 urnID = xmlCatalogUnWrapURN(pubID);
1779 if (xmlDebugCatalogs) {
1780 if (urnID == NULL)
1781 xmlGenericError(xmlGenericErrorContext,
1782 "Public URN ID %s expanded to NULL\n", pubID);
1783 else
1784 xmlGenericError(xmlGenericErrorContext,
1785 "Public URN ID expanded to %s\n", urnID);
1786 }
1787 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1788 if (urnID != NULL)
1789 xmlFree(urnID);
1790 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001791 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001792 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1793 urnID = xmlCatalogUnWrapURN(sysID);
1794 if (xmlDebugCatalogs) {
1795 if (urnID == NULL)
1796 xmlGenericError(xmlGenericErrorContext,
1797 "System URN ID %s expanded to NULL\n", sysID);
1798 else
1799 xmlGenericError(xmlGenericErrorContext,
1800 "System URN ID expanded to %s\n", urnID);
1801 }
1802 if (pubID == NULL)
1803 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1804 else if (xmlStrEqual(pubID, urnID))
1805 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1806 else {
1807 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1808 }
1809 if (urnID != NULL)
1810 xmlFree(urnID);
1811 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001812 }
1813 while (catal != NULL) {
1814 if (catal->type == XML_CATA_CATALOG) {
1815 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001816 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001817 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001818 if (catal->children != NULL) {
1819 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1820 if (ret != NULL)
1821 return(ret);
1822 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001823 }
1824 catal = catal->next;
1825 }
1826 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001827}
1828
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001829/**
1830 * xmlCatalogListXMLResolveURI:
1831 * @catal: a catalog list
1832 * @URI: the URI
1833 *
1834 * Do a complete resolution lookup of an URI for a list of catalogs
1835 *
1836 * Implements (or tries to) 7.2. URI Resolution
1837 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1838 *
1839 * Returns the URI of the resource or NULL if not found
1840 */
1841static xmlChar *
1842xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1843 xmlChar *ret = NULL;
1844 xmlChar *urnID = NULL;
1845
1846 if (catal == NULL)
1847 return(NULL);
1848 if (URI == NULL)
1849 return(NULL);
1850
1851 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1852 urnID = xmlCatalogUnWrapURN(URI);
1853 if (xmlDebugCatalogs) {
1854 if (urnID == NULL)
1855 xmlGenericError(xmlGenericErrorContext,
1856 "URN ID %s expanded to NULL\n", URI);
1857 else
1858 xmlGenericError(xmlGenericErrorContext,
1859 "URN ID expanded to %s\n", urnID);
1860 }
1861 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1862 if (urnID != NULL)
1863 xmlFree(urnID);
1864 return(ret);
1865 }
1866 while (catal != NULL) {
1867 if (catal->type == XML_CATA_CATALOG) {
1868 if (catal->children == NULL) {
1869 xmlFetchXMLCatalogFile(catal);
1870 }
1871 if (catal->children != NULL) {
1872 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1873 if (ret != NULL)
1874 return(ret);
1875 }
1876 }
1877 catal = catal->next;
1878 }
1879 return(ret);
1880}
1881
Daniel Veillard344cee72001-08-20 00:08:40 +00001882/************************************************************************
1883 * *
1884 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001885 * *
1886 ************************************************************************/
1887
1888
1889#define RAW *cur
1890#define NEXT cur++;
1891#define SKIP(x) cur += x;
1892
1893#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1894
Daniel Veillard75b96822001-10-11 18:59:45 +00001895/**
1896 * xmlParseSGMLCatalogComment:
1897 * @cur: the current character
1898 *
1899 * Skip a comment in an SGML catalog
1900 *
1901 * Returns new current character
1902 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001903static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001904xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001905 if ((cur[0] != '-') || (cur[1] != '-'))
1906 return(cur);
1907 SKIP(2);
1908 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1909 NEXT;
1910 if (cur[0] == 0) {
1911 return(NULL);
1912 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001913 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001914}
1915
Daniel Veillard75b96822001-10-11 18:59:45 +00001916/**
1917 * xmlParseSGMLCatalogPubid:
1918 * @cur: the current character
1919 * @id: the return location
1920 *
1921 * Parse an SGML catalog ID
1922 *
1923 * Returns new current character and store the value in @id
1924 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001925static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001926xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001927 xmlChar *buf = NULL;
1928 int len = 0;
1929 int size = 50;
1930 xmlChar stop;
1931 int count = 0;
1932
1933 *id = NULL;
1934
1935 if (RAW == '"') {
1936 NEXT;
1937 stop = '"';
1938 } else if (RAW == '\'') {
1939 NEXT;
1940 stop = '\'';
1941 } else {
1942 stop = ' ';
1943 }
1944 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1945 if (buf == NULL) {
1946 xmlGenericError(xmlGenericErrorContext,
1947 "malloc of %d byte failed\n", size);
1948 return(NULL);
1949 }
1950 while (xmlIsPubidChar(*cur)) {
1951 if ((*cur == stop) && (stop != ' '))
1952 break;
1953 if ((stop == ' ') && (IS_BLANK(*cur)))
1954 break;
1955 if (len + 1 >= size) {
1956 size *= 2;
1957 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1958 if (buf == NULL) {
1959 xmlGenericError(xmlGenericErrorContext,
1960 "realloc of %d byte failed\n", size);
1961 return(NULL);
1962 }
1963 }
1964 buf[len++] = *cur;
1965 count++;
1966 NEXT;
1967 }
1968 buf[len] = 0;
1969 if (stop == ' ') {
1970 if (!IS_BLANK(*cur)) {
1971 xmlFree(buf);
1972 return(NULL);
1973 }
1974 } else {
1975 if (*cur != stop) {
1976 xmlFree(buf);
1977 return(NULL);
1978 }
1979 NEXT;
1980 }
1981 *id = buf;
1982 return(cur);
1983}
1984
Daniel Veillard75b96822001-10-11 18:59:45 +00001985/**
1986 * xmlParseSGMLCatalogName:
1987 * @cur: the current character
1988 * @name: the return location
1989 *
1990 * Parse an SGML catalog name
1991 *
1992 * Returns new current character and store the value in @name
1993 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001994static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001995xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001996 xmlChar buf[XML_MAX_NAMELEN + 5];
1997 int len = 0;
1998 int c;
1999
2000 *name = NULL;
2001
2002 /*
2003 * Handler for more complex cases
2004 */
2005 c = *cur;
2006 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2007 return(NULL);
2008 }
2009
2010 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2011 (c == '.') || (c == '-') ||
2012 (c == '_') || (c == ':'))) {
2013 buf[len++] = c;
2014 cur++;
2015 c = *cur;
2016 if (len >= XML_MAX_NAMELEN)
2017 return(NULL);
2018 }
2019 *name = xmlStrndup(buf, len);
2020 return(cur);
2021}
2022
Daniel Veillard75b96822001-10-11 18:59:45 +00002023/**
2024 * xmlGetSGMLCatalogEntryType:
2025 * @name: the entry name
2026 *
2027 * Get the Catalog entry type for a given SGML Catalog name
2028 *
2029 * Returns Catalog entry type
2030 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002031static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002032xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002033 xmlCatalogEntryType type = XML_CATA_NONE;
2034 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2035 type = SGML_CATA_SYSTEM;
2036 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2037 type = SGML_CATA_PUBLIC;
2038 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2039 type = SGML_CATA_DELEGATE;
2040 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2041 type = SGML_CATA_ENTITY;
2042 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2043 type = SGML_CATA_DOCTYPE;
2044 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2045 type = SGML_CATA_LINKTYPE;
2046 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2047 type = SGML_CATA_NOTATION;
2048 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2049 type = SGML_CATA_SGMLDECL;
2050 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2051 type = SGML_CATA_DOCUMENT;
2052 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2053 type = SGML_CATA_CATALOG;
2054 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2055 type = SGML_CATA_BASE;
2056 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2057 type = SGML_CATA_DELEGATE;
2058 return(type);
2059}
2060
Daniel Veillard75b96822001-10-11 18:59:45 +00002061/**
2062 * xmlParseSGMLCatalog:
2063 * @catal: the SGML Catalog
2064 * @value: the content of the SGML Catalog serialization
2065 * @file: the filepath for the catalog
2066 * @super: should this be handled as a Super Catalog in which case
2067 * parsing is not recursive
2068 *
2069 * Parse an SGML catalog content and fill up the @catal hash table with
2070 * the new entries found.
2071 *
2072 * Returns 0 in case of success, -1 in case of error.
2073 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002074static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002075xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2076 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002077 const xmlChar *cur = value;
2078 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002079 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002080
2081 if ((cur == NULL) || (file == NULL))
2082 return(-1);
2083 base = xmlStrdup((const xmlChar *) file);
2084
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002085 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002086 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002087 if (cur[0] == 0)
2088 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002089 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002090 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002091 if (cur == NULL) {
2092 /* error */
2093 break;
2094 }
2095 } else {
2096 xmlChar *sysid = NULL;
2097 xmlChar *name = NULL;
2098 xmlCatalogEntryType type = XML_CATA_NONE;
2099
Daniel Veillardcda96922001-08-21 10:56:31 +00002100 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002101 if (name == NULL) {
2102 /* error */
2103 break;
2104 }
2105 if (!IS_BLANK(*cur)) {
2106 /* error */
2107 break;
2108 }
2109 SKIP_BLANKS;
2110 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002111 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002112 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002113 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002114 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002115 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002116 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002117 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002118 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002119 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002120 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002121 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002122 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002123 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002124 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002125 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002126 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002127 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002128 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002129 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002130 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002131 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002132 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002133 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002134 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2135 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002136 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002137 if (name == NULL) {
2138 /* error */
2139 break;
2140 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002141 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002142 continue;
2143 }
2144 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002145 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002146
2147 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002148 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002149 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002150 type = SGML_CATA_PENTITY;
2151 case SGML_CATA_PENTITY:
2152 case SGML_CATA_DOCTYPE:
2153 case SGML_CATA_LINKTYPE:
2154 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002155 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002156 if (cur == NULL) {
2157 /* error */
2158 break;
2159 }
2160 if (!IS_BLANK(*cur)) {
2161 /* error */
2162 break;
2163 }
2164 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002165 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002166 if (cur == NULL) {
2167 /* error */
2168 break;
2169 }
2170 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002171 case SGML_CATA_PUBLIC:
2172 case SGML_CATA_SYSTEM:
2173 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002174 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002175 if (cur == NULL) {
2176 /* error */
2177 break;
2178 }
2179 if (!IS_BLANK(*cur)) {
2180 /* error */
2181 break;
2182 }
2183 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002184 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002185 if (cur == NULL) {
2186 /* error */
2187 break;
2188 }
2189 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002190 case SGML_CATA_BASE:
2191 case SGML_CATA_CATALOG:
2192 case SGML_CATA_DOCUMENT:
2193 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002194 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002195 if (cur == NULL) {
2196 /* error */
2197 break;
2198 }
2199 break;
2200 default:
2201 break;
2202 }
2203 if (cur == NULL) {
2204 if (name != NULL)
2205 xmlFree(name);
2206 if (sysid != NULL)
2207 xmlFree(sysid);
2208 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002209 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002210 if (base != NULL)
2211 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002212 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002213 } else if ((type == SGML_CATA_PUBLIC) ||
2214 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002215 xmlChar *filename;
2216
2217 filename = xmlBuildURI(sysid, base);
2218 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002219 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002220
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002221 entry = xmlNewCatalogEntry(type, name, filename,
2222 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002223 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002224 if (res < 0) {
2225 xmlFreeCatalogEntry(entry);
2226 }
2227 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002228 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002229
Daniel Veillard344cee72001-08-20 00:08:40 +00002230 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002231 if (super) {
2232 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002233
Daniel Veillard82d75332001-10-08 15:01:59 +00002234 entry = xmlNewCatalogEntry(type, sysid, NULL,
2235 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002236 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002237 if (res < 0) {
2238 xmlFreeCatalogEntry(entry);
2239 }
2240 } else {
2241 xmlChar *filename;
2242
2243 filename = xmlBuildURI(sysid, base);
2244 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002245 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002246 xmlFree(filename);
2247 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002248 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002249 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002250 /*
2251 * drop anything else we won't handle it
2252 */
2253 if (name != NULL)
2254 xmlFree(name);
2255 if (sysid != NULL)
2256 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002257 }
2258 }
2259 if (base != NULL)
2260 xmlFree(base);
2261 if (cur == NULL)
2262 return(-1);
2263 return(0);
2264}
2265
Daniel Veillard75b96822001-10-11 18:59:45 +00002266/************************************************************************
2267 * *
2268 * SGML Catalog handling *
2269 * *
2270 ************************************************************************/
2271
Daniel Veillardcda96922001-08-21 10:56:31 +00002272/**
2273 * xmlCatalogGetSGMLPublic:
2274 * @catal: an SGML catalog hash
2275 * @pubId: the public ID string
2276 *
2277 * Try to lookup the system ID associated to a public ID
2278 *
2279 * Returns the system ID if found or NULL otherwise.
2280 */
2281static const xmlChar *
2282xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2283 xmlCatalogEntryPtr entry;
2284
2285 if (catal == NULL)
2286 return(NULL);
2287
2288 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2289 if (entry == NULL)
2290 return(NULL);
2291 if (entry->type == SGML_CATA_PUBLIC)
2292 return(entry->value);
2293 return(NULL);
2294}
2295
2296/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002297 * xmlCatalogGetSGMLSystem:
2298 * @catal: an SGML catalog hash
2299 * @sysId: the public ID string
2300 *
2301 * Try to lookup the catalog local reference for a system ID
2302 *
2303 * Returns the system ID if found or NULL otherwise.
2304 */
2305static const xmlChar *
2306xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2307 xmlCatalogEntryPtr entry;
2308
2309 if (catal == NULL)
2310 return(NULL);
2311
2312 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2313 if (entry == NULL)
2314 return(NULL);
2315 if (entry->type == SGML_CATA_SYSTEM)
2316 return(entry->value);
2317 return(NULL);
2318}
2319
2320/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002321 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002322 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002323 * @pubId: the public ID string
2324 * @sysId: the system ID string
2325 *
2326 * Do a complete resolution lookup of an External Identifier
2327 *
2328 * Returns the URI of the resource or NULL if not found
2329 */
2330static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002331xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2332 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002333 const xmlChar *ret = NULL;
2334
Daniel Veillard75b96822001-10-11 18:59:45 +00002335 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002336 return(NULL);
2337
2338 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002339 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002340 if (ret != NULL)
2341 return(ret);
2342 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002343 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002344 return(NULL);
2345}
2346
Daniel Veillarda7374592001-05-10 14:17:55 +00002347/************************************************************************
2348 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002349 * Specific Public interfaces *
2350 * *
2351 ************************************************************************/
2352
2353/**
2354 * xmlLoadSGMLSuperCatalog:
2355 * @filename: a file path
2356 *
2357 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2358 * references. This is only needed for manipulating SGML Super Catalogs
2359 * like adding and removing CATALOG or DELEGATE entries.
2360 *
2361 * Returns the catalog parsed or NULL in case of error
2362 */
2363xmlCatalogPtr
2364xmlLoadSGMLSuperCatalog(const char *filename)
2365{
2366 xmlChar *content;
2367 xmlCatalogPtr catal;
2368 int ret;
2369
2370 content = xmlLoadFileContent(filename);
2371 if (content == NULL)
2372 return(NULL);
2373
2374 catal = xmlNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2375 if (catal == NULL) {
2376 xmlFree(content);
2377 return(NULL);
2378 }
2379
2380 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2381 xmlFree(content);
2382 if (ret < 0) {
2383 xmlFreeCatalog(catal);
2384 return(NULL);
2385 }
2386 return (catal);
2387}
2388
2389/**
2390 * xmlLoadACatalog:
2391 * @filename: a file path
2392 *
2393 * Load the catalog and build the associated data structures.
2394 * This can be either an XML Catalog or an SGML Catalog
2395 * It will recurse in SGML CATALOG entries. On the other hand XML
2396 * Catalogs are not handled recursively.
2397 *
2398 * Returns the catalog parsed or NULL in case of error
2399 */
2400xmlCatalogPtr
2401xmlLoadACatalog(const char *filename)
2402{
2403 xmlChar *content;
2404 xmlChar *first;
2405 xmlCatalogPtr catal;
2406 int ret;
2407
2408 content = xmlLoadFileContent(filename);
2409 if (content == NULL)
2410 return(NULL);
2411
2412
2413 first = content;
2414
2415 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2416 (!(((*first >= 'A') && (*first <= 'Z')) ||
2417 ((*first >= 'a') && (*first <= 'z')))))
2418 first++;
2419
2420 if (*first != '<') {
2421 catal = xmlNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2422 if (catal == NULL) {
2423 xmlFree(content);
2424 return(NULL);
2425 }
2426 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2427 if (ret < 0) {
2428 xmlFreeCatalog(catal);
2429 xmlFree(content);
2430 return(NULL);
2431 }
2432 } else {
2433 catal = xmlNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2434 if (catal == NULL) {
2435 xmlFree(content);
2436 return(NULL);
2437 }
2438 catal->xml =
2439 xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
2440 }
2441 xmlFree(content);
2442 return (catal);
2443}
2444
2445/**
2446 * xmlExpandCatalog:
2447 * @catal: a catalog
2448 * @filename: a file path
2449 *
2450 * Load the catalog and expand the existing catal structure.
2451 * This can be either an XML Catalog or an SGML Catalog
2452 *
2453 * Returns 0 in case of success, -1 in case of error
2454 */
2455int
2456xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2457{
2458 xmlChar *content;
2459 int ret;
2460
2461 if ((catal == NULL) || (filename == NULL))
2462 return(-1);
2463
2464 content = xmlLoadFileContent(filename);
2465 if (content == NULL)
2466 return(-1);
2467
2468
2469 if (catal->type == XML_SGML_CATALOG_TYPE) {
2470 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2471 if (ret < 0) {
2472 xmlFree(content);
2473 return(-1);
2474 }
2475 } else {
2476 xmlCatalogEntryPtr tmp, cur;
2477 tmp = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
2478
2479 /* @@ THREADING LOCK catal @@ */
2480 cur = catal->xml;
2481 if (cur == NULL) {
2482 catal->xml = tmp;
2483 } else {
2484 while (cur->next != NULL) cur = cur->next;
2485 cur->next = tmp;
2486 }
2487 /* @@ THREADING RELEASE catal @@ */
2488 }
2489 xmlFree(content);
2490 return (0);
2491}
2492
2493/**
2494 * xmlACatalogResolveSystem:
2495 * @catal: a Catalog
2496 * @sysId: the public ID string
2497 *
2498 * Try to lookup the catalog resource for a system ID
2499 *
2500 * Returns the system ID if found or NULL otherwise, the value returned
2501 * must be freed by the caller.
2502 */
2503xmlChar *
2504xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2505 xmlChar *ret = NULL;
2506
2507 if ((sysID == NULL) || (catal == NULL))
2508 return(NULL);
2509
2510 if (xmlDebugCatalogs)
2511 xmlGenericError(xmlGenericErrorContext,
2512 "Resolve sysID %s\n", sysID);
2513
2514 if (catal->type == XML_XML_CATALOG_TYPE) {
2515 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2516 if (ret == XML_CATAL_BREAK)
2517 ret = NULL;
2518 } else {
2519 const xmlChar *sgml;
2520
2521 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2522 if (sgml != NULL)
2523 ret = xmlStrdup(sgml);
2524 }
2525 return(ret);
2526}
2527
2528/**
2529 * xmlACatalogResolvePublic:
2530 * @catal: a Catalog
2531 * @pubId: the public ID string
2532 *
2533 * Try to lookup the system ID associated to a public ID in that catalog
2534 *
2535 * Returns the system ID if found or NULL otherwise, the value returned
2536 * must be freed by the caller.
2537 */
2538xmlChar *
2539xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2540 xmlChar *ret = NULL;
2541
2542 if ((pubID == NULL) || (catal == NULL))
2543 return(NULL);
2544
2545 if (xmlDebugCatalogs)
2546 xmlGenericError(xmlGenericErrorContext,
2547 "Resolve pubID %s\n", pubID);
2548
2549 if (catal->type == XML_XML_CATALOG_TYPE) {
2550 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2551 if (ret == XML_CATAL_BREAK)
2552 ret = NULL;
2553 } else {
2554 const xmlChar *sgml;
2555
2556 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2557 if (sgml != NULL)
2558 ret = xmlStrdup(sgml);
2559 }
2560 return(ret);
2561}
2562
2563/**
2564 * xmlACatalogResolve:
2565 * @catal: a Catalog
2566 * @pubId: the public ID string
2567 * @sysId: the system ID string
2568 *
2569 * Do a complete resolution lookup of an External Identifier
2570 *
2571 * Returns the URI of the resource or NULL if not found, it must be freed
2572 * by the caller.
2573 */
2574xmlChar *
2575xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2576 const xmlChar * sysID)
2577{
2578 xmlChar *ret = NULL;
2579
2580 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2581 return (NULL);
2582
2583 if (xmlDebugCatalogs) {
2584 if (pubID != NULL) {
2585 xmlGenericError(xmlGenericErrorContext,
2586 "Resolve: pubID %s\n", pubID);
2587 } else {
2588 xmlGenericError(xmlGenericErrorContext,
2589 "Resolve: sysID %s\n", sysID);
2590 }
2591 }
2592
2593 if (catal->type == XML_XML_CATALOG_TYPE) {
2594 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2595 if (ret == XML_CATAL_BREAK)
2596 ret = NULL;
2597 } else {
2598 const xmlChar *sgml;
2599
2600 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2601 if (sgml != NULL)
2602 ret = xmlStrdup(sgml);
2603 }
2604 return (ret);
2605}
2606
2607/**
2608 * xmlACatalogResolveURI:
2609 * @catal: a Catalog
2610 * @pubId: the URI
2611 *
2612 * Do a complete resolution lookup of an URI
2613 *
2614 * Returns the URI of the resource or NULL if not found, it must be freed
2615 * by the caller.
2616 */
2617xmlChar *
2618xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2619 xmlChar *ret = NULL;
2620
2621 if ((URI == NULL) || (catal == NULL))
2622 return(NULL);
2623
Daniel Veillardb44025c2001-10-11 22:55:55 +00002624 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002625 xmlGenericError(xmlGenericErrorContext,
2626 "Resolve URI %s\n", URI);
2627
2628 if (catal->type == XML_XML_CATALOG_TYPE) {
2629 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2630 if (ret == XML_CATAL_BREAK)
2631 ret = NULL;
2632 } else {
2633 const xmlChar *sgml;
2634
2635 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2636 if (sgml != NULL)
2637 sgml = xmlStrdup(sgml);
2638 }
2639 return(ret);
2640}
2641
2642/**
2643 * xmlACatalogDump:
2644 * @catal: a Catalog
2645 * @out: the file.
2646 *
2647 * Free up all the memory associated with catalogs
2648 */
2649void
2650xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
2651 if (out == NULL)
2652 return;
2653
2654 if (catal->type == XML_XML_CATALOG_TYPE) {
2655 xmlDumpXMLCatalog(out, catal->xml);
2656 } else {
2657 xmlHashScan(catal->sgml,
2658 (xmlHashScanner) xmlCatalogDumpEntry, out);
2659 }
2660}
2661
2662/**
2663 * xmlACatalogAdd:
2664 * @catal: a Catalog
2665 * @type: the type of record to add to the catalog
2666 * @orig: the system, public or prefix to match
2667 * @replace: the replacement value for the match
2668 *
2669 * Add an entry in the catalog, it may overwrite existing but
2670 * different entries.
2671 *
2672 * Returns 0 if successful, -1 otherwise
2673 */
2674int
2675xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2676 const xmlChar * orig, const xmlChar * replace)
2677{
2678 int res = -1;
2679
2680 if (catal == NULL)
2681 return(-1);
2682
2683 if (catal->type == XML_XML_CATALOG_TYPE) {
2684 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2685 } else {
2686 xmlCatalogEntryType cattype;
2687
2688 cattype = xmlGetSGMLCatalogEntryType(type);
2689 if (cattype != XML_CATA_NONE) {
2690 xmlCatalogEntryPtr entry;
2691
2692 entry = xmlNewCatalogEntry(cattype, orig, replace,
2693 XML_CATA_PREFER_NONE);
2694 res = xmlHashAddEntry(catal->sgml, orig, entry);
2695 }
2696 }
2697 return (res);
2698}
2699
2700/**
2701 * xmlACatalogRemove:
2702 * @catal: a Catalog
2703 * @value: the value to remove
2704 *
2705 * Remove an entry from the catalog
2706 *
2707 * Returns the number of entries removed if successful, -1 otherwise
2708 */
2709int
2710xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2711 int res = -1;
2712
2713 if ((catal == NULL) || (value == NULL))
2714 return(-1);
2715
2716 if (catal->type == XML_XML_CATALOG_TYPE) {
2717 res = xmlDelXMLCatalog(catal->xml, value);
2718 } else {
2719 res = xmlHashRemoveEntry(catal->sgml, value,
2720 (xmlHashDeallocator) xmlFreeCatalogEntry);
2721 if (res == 0)
2722 res = 1;
2723 }
2724 return(res);
2725}
2726
2727/************************************************************************
2728 * *
2729 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002730 * *
2731 ************************************************************************/
2732
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002733/**
Daniel Veillard81463942001-10-16 12:34:39 +00002734 * xmlInitializeCatalogData:
2735 *
2736 * Do the catalog initialization only of global data, doesn't try to load
2737 * any catalog actually.
2738 * this function is not thread safe, catalog initialization should
2739 * preferably be done once at startup
2740 */
2741static void
2742xmlInitializeCatalogData(void) {
2743 if (xmlCatalogInitialized != 0)
2744 return;
2745
2746 if (getenv("XML_DEBUG_CATALOG"))
2747 xmlDebugCatalogs = 1;
2748 xmlCatalogMutex = xmlNewRMutex();
2749
2750 xmlCatalogInitialized = 1;
2751}
2752/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002753 * xmlInitializeCatalog:
2754 *
2755 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002756 * this function is not thread safe, catalog initialization should
2757 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002758 */
2759void
2760xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002761 if (xmlCatalogInitialized != 0)
2762 return;
2763
Daniel Veillard81463942001-10-16 12:34:39 +00002764 xmlInitializeCatalogData();
2765 xmlRMutexLock(xmlCatalogMutex);
2766
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002767 if (getenv("XML_DEBUG_CATALOG"))
2768 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002769
Daniel Veillard75b96822001-10-11 18:59:45 +00002770 if (xmlDefaultCatalog == NULL) {
2771 const char *catalogs;
2772 xmlCatalogPtr catal;
2773
Daniel Veillardb44025c2001-10-11 22:55:55 +00002774 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002775 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002776 catalogs = XML_XML_DEFAULT_CATALOG;
2777
2778 catal = xmlNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard81463942001-10-16 12:34:39 +00002779 if (catal == NULL) {
2780 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002781
2782 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002783 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002784
2785 xmlDefaultCatalog = catal;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002786 }
2787
Daniel Veillard81463942001-10-16 12:34:39 +00002788 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002789}
2790
Daniel Veillard82d75332001-10-08 15:01:59 +00002791
2792/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002793 * xmlLoadCatalog:
2794 * @filename: a file path
2795 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002796 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002797 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002798 * this function is not thread safe, catalog initialization should
2799 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002800 *
2801 * Returns 0 in case of success -1 in case of error
2802 */
2803int
Daniel Veillard16756b62001-10-01 07:36:25 +00002804xmlLoadCatalog(const char *filename)
2805{
Daniel Veillard75b96822001-10-11 18:59:45 +00002806 int ret;
2807 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002808
Daniel Veillard81463942001-10-16 12:34:39 +00002809 if (!xmlCatalogInitialized)
2810 xmlInitializeCatalogData();
2811
2812 xmlRMutexLock(xmlCatalogMutex);
2813
Daniel Veillard75b96822001-10-11 18:59:45 +00002814 if (xmlDefaultCatalog == NULL) {
2815 catal = xmlLoadACatalog(filename);
2816 if (catal == NULL)
2817 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002818
Daniel Veillard75b96822001-10-11 18:59:45 +00002819 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002820 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002821 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002822 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002823
Daniel Veillard75b96822001-10-11 18:59:45 +00002824 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002825 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002826 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002827}
2828
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002829/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002830 * xmlLoadCatalogs:
2831 * @paths: a list of file path separated by ':' or spaces
2832 *
2833 * Load the catalogs and makes their definitions effective for the default
2834 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002835 * this function is not thread safe, catalog initialization should
2836 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002837 */
2838void
2839xmlLoadCatalogs(const char *pathss) {
2840 const char *cur;
2841 const char *paths;
2842 xmlChar *path;
2843
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002844 if (pathss == NULL)
2845 return;
2846
Daniel Veillard81418e32001-05-22 15:08:55 +00002847 cur = pathss;
2848 while ((cur != NULL) && (*cur != 0)) {
2849 while (IS_BLANK(*cur)) cur++;
2850 if (*cur != 0) {
2851 paths = cur;
2852 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2853 cur++;
2854 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2855 if (path != NULL) {
2856 xmlLoadCatalog((const char *) path);
2857 xmlFree(path);
2858 }
2859 }
2860 while (*cur == ':')
2861 cur++;
2862 }
2863}
2864
Daniel Veillarda7374592001-05-10 14:17:55 +00002865/**
2866 * xmlCatalogCleanup:
2867 *
2868 * Free up all the memory associated with catalogs
2869 */
2870void
2871xmlCatalogCleanup(void) {
Daniel Veillard81463942001-10-16 12:34:39 +00002872 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002873 if (xmlDebugCatalogs)
2874 xmlGenericError(xmlGenericErrorContext,
2875 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002876 if (xmlCatalogXMLFiles != NULL)
2877 xmlHashFree(xmlCatalogXMLFiles, NULL);
2878 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002879 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002880 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002881 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002882 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002883 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00002884 xmlRMutexUnlock(xmlCatalogMutex);
2885 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00002886}
2887
2888/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002889 * xmlCatalogResolveSystem:
2890 * @sysId: the public ID string
2891 *
2892 * Try to lookup the catalog resource for a system ID
2893 *
2894 * Returns the system ID if found or NULL otherwise, the value returned
2895 * must be freed by the caller.
2896 */
2897xmlChar *
2898xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002899 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002900
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002901 if (!xmlCatalogInitialized)
2902 xmlInitializeCatalog();
2903
Daniel Veillard75b96822001-10-11 18:59:45 +00002904 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
2905 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002906}
2907
2908/**
2909 * xmlCatalogResolvePublic:
2910 * @pubId: the public ID string
2911 *
2912 * Try to lookup the system ID associated to a public ID
2913 *
2914 * Returns the system ID if found or NULL otherwise, the value returned
2915 * must be freed by the caller.
2916 */
2917xmlChar *
2918xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002919 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002920
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002921 if (!xmlCatalogInitialized)
2922 xmlInitializeCatalog();
2923
Daniel Veillard75b96822001-10-11 18:59:45 +00002924 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
2925 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002926}
Daniel Veillard344cee72001-08-20 00:08:40 +00002927
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002928/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002929 * xmlCatalogResolve:
2930 * @pubId: the public ID string
2931 * @sysId: the system ID string
2932 *
2933 * Do a complete resolution lookup of an External Identifier
2934 *
2935 * Returns the URI of the resource or NULL if not found, it must be freed
2936 * by the caller.
2937 */
2938xmlChar *
2939xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002940 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002941
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002942 if (!xmlCatalogInitialized)
2943 xmlInitializeCatalog();
2944
Daniel Veillard75b96822001-10-11 18:59:45 +00002945 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
2946 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002947}
2948
2949/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002950 * xmlCatalogResolveURI:
2951 * @pubId: the URI
2952 *
2953 * Do a complete resolution lookup of an URI
2954 *
2955 * Returns the URI of the resource or NULL if not found, it must be freed
2956 * by the caller.
2957 */
2958xmlChar *
2959xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002960 xmlChar *ret;
2961
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002962 if (!xmlCatalogInitialized)
2963 xmlInitializeCatalog();
2964
Daniel Veillard75b96822001-10-11 18:59:45 +00002965 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
2966 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002967}
2968
2969/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002970 * xmlCatalogDump:
2971 * @out: the file.
2972 *
2973 * Free up all the memory associated with catalogs
2974 */
2975void
2976xmlCatalogDump(FILE *out) {
2977 if (out == NULL)
2978 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00002979
Daniel Veillard75b96822001-10-11 18:59:45 +00002980 if (!xmlCatalogInitialized)
2981 xmlInitializeCatalog();
2982
2983 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00002984}
2985
2986/**
2987 * xmlCatalogAdd:
2988 * @type: the type of record to add to the catalog
2989 * @orig: the system, public or prefix to match
2990 * @replace: the replacement value for the match
2991 *
2992 * Add an entry in the catalog, it may overwrite existing but
2993 * different entries.
Daniel Veillard75b96822001-10-11 18:59:45 +00002994 * If called before any other catalo routine, allows to override the
2995 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00002996 *
2997 * Returns 0 if successful, -1 otherwise
2998 */
2999int
3000xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3001 int res = -1;
3002
Daniel Veillard81463942001-10-16 12:34:39 +00003003 if (!xmlCatalogInitialized)
3004 xmlInitializeCatalogData();
3005
3006 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003007 /*
3008 * Specific case where one want to override the default catalog
3009 * put in place by xmlInitializeCatalog();
3010 */
3011 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003012 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003013 xmlDefaultCatalog = xmlNewCatalog(XML_XML_CATALOG_TYPE,
3014 xmlCatalogDefaultPrefer);
3015 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3016 orig, xmlCatalogDefaultPrefer);
3017
Daniel Veillard81463942001-10-16 12:34:39 +00003018 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003019 return(0);
3020 }
3021
Daniel Veillard75b96822001-10-11 18:59:45 +00003022 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003023 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003024 return(res);
3025}
3026
3027/**
3028 * xmlCatalogRemove:
3029 * @value: the value to remove
3030 *
3031 * Remove an entry from the catalog
3032 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003033 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003034 */
3035int
3036xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003037 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003038
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003039 if (!xmlCatalogInitialized)
3040 xmlInitializeCatalog();
3041
Daniel Veillard81463942001-10-16 12:34:39 +00003042 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003043 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003044 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003045 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003046}
3047
3048/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003049 * xmlCatalogConvert:
3050 *
3051 * Convert all the SGML catalog entries as XML ones
3052 *
3053 * Returns the number of entries converted if successful, -1 otherwise
3054 */
3055int
3056xmlCatalogConvert(void) {
3057 int res = -1;
3058
3059 if (!xmlCatalogInitialized)
3060 xmlInitializeCatalog();
3061
Daniel Veillard81463942001-10-16 12:34:39 +00003062 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003063 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003064 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003065 return(res);
3066}
3067
Daniel Veillard75b96822001-10-11 18:59:45 +00003068/************************************************************************
3069 * *
3070 * Public interface manipulating the common preferences *
3071 * *
3072 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003073
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003074/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003075 * xmlCatalogGetDefaults:
3076 *
3077 * Used to get the user preference w.r.t. to what catalogs should
3078 * be accepted
3079 *
3080 * Returns the current xmlCatalogAllow value
3081 */
3082xmlCatalogAllow
3083xmlCatalogGetDefaults(void) {
Daniel Veillard81463942001-10-16 12:34:39 +00003084 if (!xmlCatalogInitialized)
3085 xmlInitializeCatalog();
3086
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003087 return(xmlCatalogDefaultAllow);
3088}
3089
3090/**
3091 * xmlCatalogSetDefaults:
3092 *
3093 * Used to set the user preference w.r.t. to what catalogs should
3094 * be accepted
3095 */
3096void
3097xmlCatalogSetDefaults(xmlCatalogAllow allow) {
3098 if (!xmlCatalogInitialized)
3099 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003100
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003101 if (xmlDebugCatalogs) {
3102 switch (allow) {
3103 case XML_CATA_ALLOW_NONE:
3104 xmlGenericError(xmlGenericErrorContext,
3105 "Disabling catalog usage\n");
3106 break;
3107 case XML_CATA_ALLOW_GLOBAL:
3108 xmlGenericError(xmlGenericErrorContext,
3109 "Allowing only global catalogs\n");
3110 break;
3111 case XML_CATA_ALLOW_DOCUMENT:
3112 xmlGenericError(xmlGenericErrorContext,
3113 "Allowing only catalogs from the document\n");
3114 break;
3115 case XML_CATA_ALLOW_ALL:
3116 xmlGenericError(xmlGenericErrorContext,
3117 "Allowing all catalogs\n");
3118 break;
3119 }
3120 }
3121 xmlCatalogDefaultAllow = allow;
3122}
3123
3124/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003125 * xmlCatalogSetDefaultPrefer:
3126 * @prefer: the default preference for delegation
3127 *
3128 * Allows to set the preference between public and system for deletion
3129 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003130 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003131 *
3132 * Returns the previous value of the default preference for delegation
3133 */
3134xmlCatalogPrefer
3135xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3136 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3137
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003138 if (!xmlCatalogInitialized)
3139 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003140
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003141 if (prefer == XML_CATA_PREFER_NONE)
3142 return(ret);
3143
3144 if (xmlDebugCatalogs) {
3145 switch (prefer) {
3146 case XML_CATA_PREFER_PUBLIC:
3147 xmlGenericError(xmlGenericErrorContext,
3148 "Setting catalog preference to PUBLIC\n");
3149 break;
3150 case XML_CATA_PREFER_SYSTEM:
3151 xmlGenericError(xmlGenericErrorContext,
3152 "Setting catalog preference to SYSTEM\n");
3153 break;
3154 case XML_CATA_PREFER_NONE:
3155 break;
3156 }
3157 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003158 xmlCatalogDefaultPrefer = prefer;
3159 return(ret);
3160}
3161
3162/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003163 * xmlCatalogSetDebug:
3164 * @level: the debug level of catalogs required
3165 *
3166 * Used to set the debug level for catalog operation, 0 disable
3167 * debugging, 1 enable it
3168 *
3169 * Returns the previous value of the catalog debugging level
3170 */
3171int
3172xmlCatalogSetDebug(int level) {
3173 int ret = xmlDebugCatalogs;
3174
Daniel Veillard81463942001-10-16 12:34:39 +00003175 if (!xmlCatalogInitialized)
3176 xmlInitializeCatalog();
3177
Daniel Veillard344cee72001-08-20 00:08:40 +00003178 if (level <= 0)
3179 xmlDebugCatalogs = 0;
3180 else
3181 xmlDebugCatalogs = level;
3182 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003183}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003184
Daniel Veillard75b96822001-10-11 18:59:45 +00003185/************************************************************************
3186 * *
3187 * Minimal interfaces used for per-document catalogs by the parser *
3188 * *
3189 ************************************************************************/
3190
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003191/**
3192 * xmlCatalogFreeLocal:
3193 * @catalogs: a document's list of catalogs
3194 *
3195 * Free up the memory associated to the catalog list
3196 */
3197void
3198xmlCatalogFreeLocal(void *catalogs) {
3199 xmlCatalogEntryPtr catal;
3200
Daniel Veillard81463942001-10-16 12:34:39 +00003201 if (!xmlCatalogInitialized)
3202 xmlInitializeCatalog();
3203
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003204 catal = (xmlCatalogEntryPtr) catalogs;
3205 if (catal != NULL)
3206 xmlFreeCatalogEntryList(catal);
3207}
3208
3209
3210/**
3211 * xmlCatalogAddLocal:
3212 * @catalogs: a document's list of catalogs
3213 * @URL: the URL to a new local catalog
3214 *
3215 * Add the new entry to the catalog list
3216 *
3217 * Returns the updated list
3218 */
3219void *
3220xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3221 xmlCatalogEntryPtr catal, add;
3222
3223 if (!xmlCatalogInitialized)
3224 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003225
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003226 if (URL == NULL)
3227 return(catalogs);
3228
3229 if (xmlDebugCatalogs)
3230 xmlGenericError(xmlGenericErrorContext,
3231 "Adding document catalog %s\n", URL);
3232
3233 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
3234 xmlCatalogDefaultPrefer);
3235 if (add == NULL)
3236 return(catalogs);
3237
3238 catal = (xmlCatalogEntryPtr) catalogs;
3239 if (catal == NULL)
3240 return((void *) add);
3241
3242 while (catal->next != NULL)
3243 catal = catal->next;
3244 catal->next = add;
3245 return(catalogs);
3246}
3247
3248/**
3249 * xmlCatalogLocalResolve:
3250 * @catalogs: a document's list of catalogs
3251 * @pubId: the public ID string
3252 * @sysId: the system ID string
3253 *
3254 * Do a complete resolution lookup of an External Identifier using a
3255 * document's private catalog list
3256 *
3257 * Returns the URI of the resource or NULL if not found, it must be freed
3258 * by the caller.
3259 */
3260xmlChar *
3261xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3262 const xmlChar *sysID) {
3263 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003264 xmlChar *ret;
3265
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003266 if (!xmlCatalogInitialized)
3267 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003268
Daniel Veillard81463942001-10-16 12:34:39 +00003269 if ((pubID == NULL) && (sysID == NULL))
3270 return(NULL);
3271
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003272 if (xmlDebugCatalogs) {
3273 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003274 xmlGenericError(xmlGenericErrorContext,
3275 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003276 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003277 xmlGenericError(xmlGenericErrorContext,
3278 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003279 }
3280 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003281
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003282 catal = (xmlCatalogEntryPtr) catalogs;
3283 if (catal == NULL)
3284 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003285 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3286 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3287 return(ret);
3288 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003289}
3290
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003291/**
3292 * xmlCatalogLocalResolveURI:
3293 * @catalogs: a document's list of catalogs
3294 * @pubId: the URI
3295 *
3296 * Do a complete resolution lookup of an URI using a
3297 * document's private catalog list
3298 *
3299 * Returns the URI of the resource or NULL if not found, it must be freed
3300 * by the caller.
3301 */
3302xmlChar *
3303xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3304 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003305 xmlChar *ret;
3306
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003307 if (!xmlCatalogInitialized)
3308 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003309
Daniel Veillard81463942001-10-16 12:34:39 +00003310 if (URI == NULL)
3311 return(NULL);
3312
Daniel Veillard6990bf32001-08-23 21:17:48 +00003313 if (xmlDebugCatalogs)
3314 xmlGenericError(xmlGenericErrorContext,
3315 "Resolve URI %s\n", URI);
3316
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003317 catal = (xmlCatalogEntryPtr) catalogs;
3318 if (catal == NULL)
3319 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003320 ret = xmlCatalogListXMLResolveURI(catal, URI);
3321 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3322 return(ret);
3323 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003324}
3325
Daniel Veillard75b96822001-10-11 18:59:45 +00003326/************************************************************************
3327 * *
3328 * Deprecated interfaces *
3329 * *
3330 ************************************************************************/
3331/**
3332 * xmlCatalogGetSystem:
3333 * @pubId: the public ID string
3334 *
3335 * Try to lookup the system ID associated to a public ID
3336 * DEPRECATED, use xmlCatalogResolveSystem()
3337 *
3338 * Returns the system ID if found or NULL otherwise.
3339 */
3340const xmlChar *
3341xmlCatalogGetSystem(const xmlChar *sysID) {
3342 xmlChar *ret;
3343 static xmlChar result[1000];
3344 static int msg = 0;
3345
Daniel Veillard81463942001-10-16 12:34:39 +00003346 if (!xmlCatalogInitialized)
3347 xmlInitializeCatalog();
3348
Daniel Veillard75b96822001-10-11 18:59:45 +00003349 if (msg == 0) {
3350 xmlGenericError(xmlGenericErrorContext,
3351 "Use of deprecated xmlCatalogGetSystem() call\n");
3352 msg++;
3353 }
3354
3355 if (sysID == NULL)
3356 return(NULL);
3357
Daniel Veillard75b96822001-10-11 18:59:45 +00003358 /*
3359 * Check first the XML catalogs
3360 */
3361 if (xmlDefaultCatalog != NULL) {
3362 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3363 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3364 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3365 result[sizeof(result) - 1] = 0;
3366 return(result);
3367 }
3368 }
3369
3370 if (xmlDefaultCatalog != NULL)
3371 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3372 return(NULL);
3373}
3374
3375/**
3376 * xmlCatalogGetPublic:
3377 * @pubId: the public ID string
3378 *
3379 * Try to lookup the system ID associated to a public ID
3380 * DEPRECATED, use xmlCatalogResolvePublic()
3381 *
3382 * Returns the system ID if found or NULL otherwise.
3383 */
3384const xmlChar *
3385xmlCatalogGetPublic(const xmlChar *pubID) {
3386 xmlChar *ret;
3387 static xmlChar result[1000];
3388 static int msg = 0;
3389
Daniel Veillard81463942001-10-16 12:34:39 +00003390 if (!xmlCatalogInitialized)
3391 xmlInitializeCatalog();
3392
Daniel Veillard75b96822001-10-11 18:59:45 +00003393 if (msg == 0) {
3394 xmlGenericError(xmlGenericErrorContext,
3395 "Use of deprecated xmlCatalogGetPublic() call\n");
3396 msg++;
3397 }
3398
3399 if (pubID == NULL)
3400 return(NULL);
3401
Daniel Veillard75b96822001-10-11 18:59:45 +00003402 /*
3403 * Check first the XML catalogs
3404 */
3405 if (xmlDefaultCatalog != NULL) {
3406 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3407 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3408 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3409 result[sizeof(result) - 1] = 0;
3410 return(result);
3411 }
3412 }
3413
3414 if (xmlDefaultCatalog != NULL)
3415 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3416 return(NULL);
3417}
3418
Daniel Veillarda7374592001-05-10 14:17:55 +00003419#endif /* LIBXML_CATALOG_ENABLED */