blob: a8b9e74b0d5a9aedab56d0bcd9649f867be19de3 [file] [log] [blame]
Daniel Veillarda7374592001-05-10 14:17:55 +00001/**
2 * catalog.c: set of generic Catalog related routines
3 *
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
6 *
Daniel Veillard344cee72001-08-20 00:08:40 +00007 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
9 *
Daniel Veillarda7374592001-05-10 14:17:55 +000010 * See Copyright for the status of this software.
11 *
12 * Daniel.Veillard@imag.fr
13 */
14
15#include "libxml.h"
16
17#ifdef LIBXML_CATALOG_ENABLED
18#ifdef HAVE_SYS_TYPES_H
19#include <sys/types.h>
20#endif
21#ifdef HAVE_SYS_STAT_H
22#include <sys/stat.h>
23#endif
24#ifdef HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27#ifdef HAVE_FCNTL_H
28#include <fcntl.h>
29#endif
Daniel Veillardc0631a62001-09-20 13:56:06 +000030#ifdef HAVE_STDLIB_H
31#include <stdlib.h>
32#endif
Daniel Veillarda7374592001-05-10 14:17:55 +000033#include <string.h>
34#include <libxml/xmlmemory.h>
35#include <libxml/hash.h>
36#include <libxml/uri.h>
37#include <libxml/parserInternals.h>
38#include <libxml/catalog.h>
39#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000040#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000041#include <libxml/globals.h>
Daniel Veillarda7374592001-05-10 14:17:55 +000042
Daniel Veillard6990bf32001-08-23 21:17:48 +000043#define MAX_DELEGATE 50
44
Daniel Veillard344cee72001-08-20 00:08:40 +000045/**
46 * TODO:
47 *
48 * macro to flag unimplemented blocks
49 */
50#define TODO \
51 xmlGenericError(xmlGenericErrorContext, \
52 "Unimplemented block at %s:%d\n", \
53 __FILE__, __LINE__);
54
Daniel Veillardcda96922001-08-21 10:56:31 +000055#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000056#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000057#ifndef XML_XML_DEFAULT_CATALOG
58#define XML_XML_DEFAULT_CATALOG "/etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000059#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000060#ifndef XML_SGML_DEFAULT_CATALOG
61#define XML_SGML_DEFAULT_CATALOG "/etc/sgml/catalog"
62#endif
63
Daniel Veillard85c11fa2001-10-16 21:03:08 +000064static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000065
Daniel Veillarda7374592001-05-10 14:17:55 +000066/************************************************************************
67 * *
68 * Types, all private *
69 * *
70 ************************************************************************/
71
72typedef enum {
73 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000074 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000075 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000076 XML_CATA_NEXT_CATALOG,
77 XML_CATA_PUBLIC,
78 XML_CATA_SYSTEM,
79 XML_CATA_REWRITE_SYSTEM,
80 XML_CATA_DELEGATE_PUBLIC,
81 XML_CATA_DELEGATE_SYSTEM,
82 XML_CATA_URI,
83 XML_CATA_REWRITE_URI,
84 XML_CATA_DELEGATE_URI,
85 SGML_CATA_SYSTEM,
86 SGML_CATA_PUBLIC,
87 SGML_CATA_ENTITY,
88 SGML_CATA_PENTITY,
89 SGML_CATA_DOCTYPE,
90 SGML_CATA_LINKTYPE,
91 SGML_CATA_NOTATION,
92 SGML_CATA_DELEGATE,
93 SGML_CATA_BASE,
94 SGML_CATA_CATALOG,
95 SGML_CATA_DOCUMENT,
96 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000097} xmlCatalogEntryType;
98
99typedef struct _xmlCatalogEntry xmlCatalogEntry;
100typedef xmlCatalogEntry *xmlCatalogEntryPtr;
101struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000102 struct _xmlCatalogEntry *next;
103 struct _xmlCatalogEntry *parent;
104 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000105 xmlCatalogEntryType type;
106 xmlChar *name;
107 xmlChar *value;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000108 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000109 int dealloc;
Daniel Veillarda7374592001-05-10 14:17:55 +0000110};
111
Daniel Veillard75b96822001-10-11 18:59:45 +0000112typedef enum {
113 XML_XML_CATALOG_TYPE = 1,
114 XML_SGML_CATALOG_TYPE
115} xmlCatalogType;
116
117#define XML_MAX_SGML_CATA_DEPTH 10
118struct _xmlCatalog {
119 xmlCatalogType type; /* either XML or SGML */
120
121 /*
122 * SGML Catalogs are stored as a simple hash table of catalog entries
123 * Catalog stack to check against overflows when building the
124 * SGML catalog
125 */
126 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
127 int catalNr; /* Number of current catal streams */
128 int catalMax; /* Max number of catal streams */
129 xmlHashTablePtr sgml;
130
131 /*
132 * XML Catalogs are stored as a tree of Catalog entries
133 */
134 xmlCatalogPrefer prefer;
135 xmlCatalogEntryPtr xml;
136};
137
138/************************************************************************
139 * *
140 * Global variables *
141 * *
142 ************************************************************************/
143
Daniel Veillard81463942001-10-16 12:34:39 +0000144/*
145 * Those are preferences
146 */
147static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000148static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000149static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000150
151/*
152 * Hash table containing all the trees of XML catalogs parsed by
153 * the application.
154 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000155static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000156
157/*
158 * The default catalog in use by the application
159 */
160static xmlCatalogPtr xmlDefaultCatalog = NULL;
161
162/*
Daniel Veillard81463942001-10-16 12:34:39 +0000163 * A mutex for modifying the shared global catalog(s)
164 * xmlDefaultCatalog tree.
165 * It also protects xmlCatalogXMLFiles
166 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
167 */
168static xmlRMutexPtr xmlCatalogMutex = NULL;
169
170/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000171 * Whether the catalog support was initialized.
172 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000173static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000174
Daniel Veillarda7374592001-05-10 14:17:55 +0000175
176/************************************************************************
177 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000178 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000179 * *
180 ************************************************************************/
181
Daniel Veillard75b96822001-10-11 18:59:45 +0000182/**
183 * xmlNewCatalogEntry:
184 * @type: type of entry
185 * @name: name of the entry
186 * @value: value of the entry
187 * @prefer: the PUBLIC vs. SYSTEM current preference value
188 *
189 * create a new Catalog entry, this type is shared both by XML and
190 * SGML catalogs, but the acceptable types values differs.
191 *
192 * Returns the xmlCatalogEntryPtr or NULL in case of error
193 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000194static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000195xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000196 const xmlChar *value, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000197 xmlCatalogEntryPtr ret;
198
199 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
200 if (ret == NULL) {
201 xmlGenericError(xmlGenericErrorContext,
202 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
203 return(NULL);
204 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000205 ret->next = NULL;
206 ret->parent = NULL;
207 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000208 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000209 if (name != NULL)
210 ret->name = xmlStrdup(name);
211 else
212 ret->name = NULL;
213 if (value != NULL)
214 ret->value = xmlStrdup(value);
215 else
216 ret->value = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000217 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000218 ret->dealloc = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +0000219 return(ret);
220}
221
222static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000223xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
224
Daniel Veillard75b96822001-10-11 18:59:45 +0000225/**
226 * xmlFreeCatalogEntry:
227 * @ret: a Catalog entry
228 *
229 * Free the memory allocated to a Catalog entry
230 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000231static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000232xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
233 if (ret == NULL)
234 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000235 /*
236 * Entries stored in the file hash must be dealloacted
237 * only by the file hash cleaner !
238 */
239 if (ret->dealloc == 1)
240 return;
241
242 if (xmlDebugCatalogs) {
243 if (ret->name != NULL)
244 xmlGenericError(xmlGenericErrorContext,
245 "Free catalog entry %s\n", ret->name);
246 else if (ret->value != NULL)
247 xmlGenericError(xmlGenericErrorContext,
248 "Free catalog entry %s\n", ret->value);
249 else
250 xmlGenericError(xmlGenericErrorContext,
251 "Free catalog entry\n");
252 }
253
Daniel Veillarda7374592001-05-10 14:17:55 +0000254 if (ret->name != NULL)
255 xmlFree(ret->name);
256 if (ret->value != NULL)
257 xmlFree(ret->value);
258 xmlFree(ret);
259}
260
Daniel Veillard75b96822001-10-11 18:59:45 +0000261/**
262 * xmlFreeCatalogEntryList:
263 * @ret: a Catalog entry list
264 *
265 * Free the memory allocated to a full chained list of Catalog entries
266 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000267static void
268xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
269 xmlCatalogEntryPtr next;
270
271 while (ret != NULL) {
272 next = ret->next;
273 xmlFreeCatalogEntry(ret);
274 ret = next;
275 }
276}
277
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000278/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000279 * xmlFreeCatalogHashEntryList:
280 * @ret: a Catalog entry list
281 *
282 * Free the memory allocated to list of Catalog entries from the
283 * catalog file hash.
284 */
285static void
286xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
287 xmlCatalogEntryPtr children, next;
288
289 if (catal == NULL)
290 return;
291
292 children = catal->children;
293 while (children != NULL) {
294 next = children->next;
295 children->dealloc = 0;
296 children->children = NULL;
297 xmlFreeCatalogEntry(children);
298 children = next;
299 }
300 catal->dealloc = 0;
301 xmlFreeCatalogEntry(catal);
302}
303
304/**
Daniel Veillard75b96822001-10-11 18:59:45 +0000305 * xmlNewCatalog:
306 * @type: type of catalog
307 * @prefer: the PUBLIC vs. SYSTEM current preference value
308 *
309 * create a new Catalog, this type is shared both by XML and
310 * SGML catalogs, but the acceptable types values differs.
311 *
312 * Returns the xmlCatalogPtr or NULL in case of error
313 */
314static xmlCatalogPtr
315xmlNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
316 xmlCatalogPtr ret;
317
318 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
319 if (ret == NULL) {
320 xmlGenericError(xmlGenericErrorContext,
321 "malloc of %d byte failed\n", sizeof(xmlCatalog));
322 return(NULL);
323 }
324 memset(ret, 0, sizeof(xmlCatalog));
325 ret->type = type;
326 ret->catalNr = 0;
327 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
328 ret->prefer = prefer;
329 return(ret);
330}
331
332/**
333 * xmlFreeCatalog:
334 * @catal: a Catalog entry
335 *
336 * Free the memory allocated to a Catalog
337 */
338void
339xmlFreeCatalog(xmlCatalogPtr catal) {
340 if (catal == NULL)
341 return;
342 if (catal->xml != NULL)
343 xmlFreeCatalogEntryList(catal->xml);
344 if (catal->sgml != NULL)
345 xmlHashFree(catal->sgml,
346 (xmlHashDeallocator) xmlFreeCatalogEntry);
347 xmlFree(catal);
348}
349
350/************************************************************************
351 * *
352 * Serializing Catalogs *
353 * *
354 ************************************************************************/
355
356/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000357 * xmlCatalogDumpEntry:
358 * @entry: the
359 * @out: the file.
360 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000361 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000362 */
363static void
364xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
365 if ((entry == NULL) || (out == NULL))
366 return;
367 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000368 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000369 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000370 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000371 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000372 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000373 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000374 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000375 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000376 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000377 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000378 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000379 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000380 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000381 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000382 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000383 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000384 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000385 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000386 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000387 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000388 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000389 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000390 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000391 fprintf(out, "SGMLDECL "); break;
392 default:
393 return;
394 }
395 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000396 case SGML_CATA_ENTITY:
397 case SGML_CATA_PENTITY:
398 case SGML_CATA_DOCTYPE:
399 case SGML_CATA_LINKTYPE:
400 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000401 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000402 case SGML_CATA_PUBLIC:
403 case SGML_CATA_SYSTEM:
404 case SGML_CATA_SGMLDECL:
405 case SGML_CATA_DOCUMENT:
406 case SGML_CATA_CATALOG:
407 case SGML_CATA_BASE:
408 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000409 fprintf(out, "\"%s\"", entry->name); break;
410 default:
411 break;
412 }
413 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000414 case SGML_CATA_ENTITY:
415 case SGML_CATA_PENTITY:
416 case SGML_CATA_DOCTYPE:
417 case SGML_CATA_LINKTYPE:
418 case SGML_CATA_NOTATION:
419 case SGML_CATA_PUBLIC:
420 case SGML_CATA_SYSTEM:
421 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000422 fprintf(out, " \"%s\"", entry->value); break;
423 default:
424 break;
425 }
426 fprintf(out, "\n");
427}
428
Daniel Veillard75b96822001-10-11 18:59:45 +0000429static int
430xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
431 int ret;
432 xmlDocPtr doc;
433 xmlNsPtr ns;
434 xmlDtdPtr dtd;
435 xmlNodePtr node, catalog;
436 xmlOutputBufferPtr buf;
437 xmlCatalogEntryPtr cur;
438
439 /*
440 * Rebuild a catalog
441 */
442 doc = xmlNewDoc(NULL);
443 if (doc == NULL)
444 return(-1);
445 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
446 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
447BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
448
449 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
450
451 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
452 if (ns == NULL) {
453 xmlFreeDoc(doc);
454 return(-1);
455 }
456 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
457 if (catalog == NULL) {
458 xmlFreeNs(ns);
459 xmlFreeDoc(doc);
460 return(-1);
461 }
462 catalog->nsDef = ns;
463 xmlAddChild((xmlNodePtr) doc, catalog);
464
465 /*
466 * add all the catalog entries
467 */
468 cur = catal;
469 while (cur != NULL) {
470 switch (cur->type) {
471 case XML_CATA_BROKEN_CATALOG:
472 case XML_CATA_CATALOG:
473 if (cur == catal) {
474 cur = cur->children;
475 continue;
476 }
477 break;
478 case XML_CATA_NEXT_CATALOG:
479 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
480 xmlSetProp(node, BAD_CAST "catalog", cur->value);
481 xmlAddChild(catalog, node);
482 break;
483 case XML_CATA_NONE:
484 break;
485 case XML_CATA_PUBLIC:
486 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
487 xmlSetProp(node, BAD_CAST "publicId", cur->name);
488 xmlSetProp(node, BAD_CAST "uri", cur->value);
489 xmlAddChild(catalog, node);
490 break;
491 case XML_CATA_SYSTEM:
492 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
493 xmlSetProp(node, BAD_CAST "systemId", cur->name);
494 xmlSetProp(node, BAD_CAST "uri", cur->value);
495 xmlAddChild(catalog, node);
496 break;
497 case XML_CATA_REWRITE_SYSTEM:
498 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
499 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
500 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
501 xmlAddChild(catalog, node);
502 break;
503 case XML_CATA_DELEGATE_PUBLIC:
504 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
505 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
506 xmlSetProp(node, BAD_CAST "catalog", cur->value);
507 xmlAddChild(catalog, node);
508 break;
509 case XML_CATA_DELEGATE_SYSTEM:
510 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
511 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
512 xmlSetProp(node, BAD_CAST "catalog", cur->value);
513 xmlAddChild(catalog, node);
514 break;
515 case XML_CATA_URI:
516 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
517 xmlSetProp(node, BAD_CAST "name", cur->name);
518 xmlSetProp(node, BAD_CAST "uri", cur->value);
519 xmlAddChild(catalog, node);
520 break;
521 case XML_CATA_REWRITE_URI:
522 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
523 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
524 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
525 xmlAddChild(catalog, node);
526 break;
527 case XML_CATA_DELEGATE_URI:
528 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
529 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
530 xmlSetProp(node, BAD_CAST "catalog", cur->value);
531 xmlAddChild(catalog, node);
532 break;
533 case SGML_CATA_SYSTEM:
534 case SGML_CATA_PUBLIC:
535 case SGML_CATA_ENTITY:
536 case SGML_CATA_PENTITY:
537 case SGML_CATA_DOCTYPE:
538 case SGML_CATA_LINKTYPE:
539 case SGML_CATA_NOTATION:
540 case SGML_CATA_DELEGATE:
541 case SGML_CATA_BASE:
542 case SGML_CATA_CATALOG:
543 case SGML_CATA_DOCUMENT:
544 case SGML_CATA_SGMLDECL:
545 break;
546 }
547 cur = cur->next;
548 }
549
550 /*
551 * reserialize it
552 */
553 buf = xmlOutputBufferCreateFile(out, NULL);
554 if (buf == NULL) {
555 xmlFreeDoc(doc);
556 return(-1);
557 }
558 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
559
560 /*
561 * Free it
562 */
563 xmlFreeDoc(doc);
564
565 return(ret);
566}
567
568/************************************************************************
569 * *
570 * Converting SGML Catalogs to XML *
571 * *
572 ************************************************************************/
573
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000574/**
575 * xmlCatalogConvertEntry:
576 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000577 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000578 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000579 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000580 */
581static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000582xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
583 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
584 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000585 return;
586 switch (entry->type) {
587 case SGML_CATA_ENTITY:
588 entry->type = XML_CATA_PUBLIC;
589 break;
590 case SGML_CATA_PENTITY:
591 entry->type = XML_CATA_PUBLIC;
592 break;
593 case SGML_CATA_DOCTYPE:
594 entry->type = XML_CATA_PUBLIC;
595 break;
596 case SGML_CATA_LINKTYPE:
597 entry->type = XML_CATA_PUBLIC;
598 break;
599 case SGML_CATA_NOTATION:
600 entry->type = XML_CATA_PUBLIC;
601 break;
602 case SGML_CATA_PUBLIC:
603 entry->type = XML_CATA_PUBLIC;
604 break;
605 case SGML_CATA_SYSTEM:
606 entry->type = XML_CATA_SYSTEM;
607 break;
608 case SGML_CATA_DELEGATE:
609 entry->type = XML_CATA_DELEGATE_PUBLIC;
610 break;
611 case SGML_CATA_CATALOG:
612 entry->type = XML_CATA_CATALOG;
613 break;
614 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000615 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000616 (xmlHashDeallocator) xmlFreeCatalogEntry);
617 return;
618 }
619 /*
620 * Conversion successful, remove from the SGML catalog
621 * and add it to the default XML one
622 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000623 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
624 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000625 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000626 if (catal->xml->children == NULL)
627 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000628 else {
629 xmlCatalogEntryPtr prev;
630
Daniel Veillard75b96822001-10-11 18:59:45 +0000631 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000632 while (prev->next != NULL)
633 prev = prev->next;
634 prev->next = entry;
635 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000636}
637
638/**
639 * xmlConvertSGMLCatalog:
640 * @catal: the catalog
641 *
642 * Convert all the SGML catalog entries as XML ones
643 *
644 * Returns the number of entries converted if successful, -1 otherwise
645 */
646int
647xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
648
649 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
650 return(-1);
651
652 if (xmlDebugCatalogs) {
653 xmlGenericError(xmlGenericErrorContext,
654 "Converting SGML catalog to XML\n");
655 }
656 xmlHashScan(catal->sgml,
657 (xmlHashScanner) xmlCatalogConvertEntry,
658 &catal);
659 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000660}
661
Daniel Veillarda7374592001-05-10 14:17:55 +0000662/************************************************************************
663 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000664 * Helper function *
665 * *
666 ************************************************************************/
667
668/**
669 * xmlCatalogUnWrapURN:
670 * @urn: an "urn:publicid:" to unwrapp
671 *
672 * Expand the URN into the equivalent Public Identifier
673 *
674 * Returns the new identifier or NULL, the string must be deallocated
675 * by the caller.
676 */
677static xmlChar *
678xmlCatalogUnWrapURN(const xmlChar *urn) {
679 xmlChar result[2000];
680 unsigned int i = 0;
681
682 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
683 return(NULL);
684 urn += sizeof(XML_URN_PUBID) - 1;
685
686 while (*urn != 0) {
687 if (i > sizeof(result) - 3)
688 break;
689 if (*urn == '+') {
690 result[i++] = ' ';
691 urn++;
692 } else if (*urn == ':') {
693 result[i++] = '/';
694 result[i++] = '/';
695 urn++;
696 } else if (*urn == ';') {
697 result[i++] = ':';
698 result[i++] = ':';
699 urn++;
700 } else if (*urn == '%') {
701 if ((urn[1] == '2') && (urn[1] == 'B'))
702 result[i++] = '+';
703 else if ((urn[1] == '3') && (urn[1] == 'A'))
704 result[i++] = ':';
705 else if ((urn[1] == '2') && (urn[1] == 'F'))
706 result[i++] = '/';
707 else if ((urn[1] == '3') && (urn[1] == 'B'))
708 result[i++] = ';';
709 else if ((urn[1] == '2') && (urn[1] == '7'))
710 result[i++] = '\'';
711 else if ((urn[1] == '3') && (urn[1] == 'F'))
712 result[i++] = '?';
713 else if ((urn[1] == '2') && (urn[1] == '3'))
714 result[i++] = '#';
715 else if ((urn[1] == '2') && (urn[1] == '5'))
716 result[i++] = '%';
717 else {
718 result[i++] = *urn;
719 urn++;
720 continue;
721 }
722 urn += 3;
723 } else {
724 result[i++] = *urn;
725 urn++;
726 }
727 }
728 result[i] = 0;
729
730 return(xmlStrdup(result));
731}
732
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000733/**
734 * xmlParseCatalogFile:
735 * @filename: the filename
736 *
737 * parse an XML file and build a tree. It's like xmlParseFile()
738 * except it bypass all catalog lookups.
739 *
740 * Returns the resulting document tree or NULL in case of error
741 */
742
743xmlDocPtr
744xmlParseCatalogFile(const char *filename) {
745 xmlDocPtr ret;
746 xmlParserCtxtPtr ctxt;
747 char *directory = NULL;
748 xmlParserInputPtr inputStream;
749 xmlParserInputBufferPtr buf;
750
751 ctxt = xmlNewParserCtxt();
752 if (ctxt == NULL) {
753 if (xmlDefaultSAXHandler.error != NULL) {
754 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
755 }
756 return(NULL);
757 }
758
759 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
760 if (buf == NULL) {
761 xmlFreeParserCtxt(ctxt);
762 return(NULL);
763 }
764
765 inputStream = xmlNewInputStream(ctxt);
766 if (inputStream == NULL) {
767 xmlFreeParserCtxt(ctxt);
768 return(NULL);
769 }
770
771 inputStream->filename = xmlMemStrdup(filename);
772 inputStream->buf = buf;
773 inputStream->base = inputStream->buf->buffer->content;
774 inputStream->cur = inputStream->buf->buffer->content;
775 inputStream->end =
776 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
777
778 inputPush(ctxt, inputStream);
779 if ((ctxt->directory == NULL) && (directory == NULL))
780 directory = xmlParserGetDirectory(filename);
781 if ((ctxt->directory == NULL) && (directory != NULL))
782 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000783 ctxt->valid = 0;
784 ctxt->validate = 0;
785 ctxt->loadsubset = 0;
786 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000787
788 xmlParseDocument(ctxt);
789
790 if (ctxt->wellFormed)
791 ret = ctxt->myDoc;
792 else {
793 ret = NULL;
794 xmlFreeDoc(ctxt->myDoc);
795 ctxt->myDoc = NULL;
796 }
797 xmlFreeParserCtxt(ctxt);
798
799 return(ret);
800}
801
Daniel Veillard75b96822001-10-11 18:59:45 +0000802/**
803 * xmlLoadFileContent:
804 * @filename: a file path
805 *
806 * Load a file content into memory.
807 *
808 * Returns a pointer to the 0 terminated string or NULL in case of error
809 */
810static xmlChar *
811xmlLoadFileContent(const char *filename)
812{
813#ifdef HAVE_STAT
814 int fd;
815#else
816 FILE *fd;
817#endif
818 int len;
819 long size;
820
821#ifdef HAVE_STAT
822 struct stat info;
823#endif
824 xmlChar *content;
825
826 if (filename == NULL)
827 return (NULL);
828
829#ifdef HAVE_STAT
830 if (stat(filename, &info) < 0)
831 return (NULL);
832#endif
833
834#ifdef HAVE_STAT
835 if ((fd = open(filename, O_RDONLY)) < 0) {
836#else
837 if ((fd = fopen(filename, "rb")) == NULL) {
838#endif
839 return (NULL);
840 }
841#ifdef HAVE_STAT
842 size = info.st_size;
843#else
844 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
845 fclose(fd);
846 return (NULL);
847 }
848#endif
849 content = xmlMalloc(size + 10);
850 if (content == NULL) {
851 xmlGenericError(xmlGenericErrorContext,
852 "malloc of %d byte failed\n", size + 10);
853 return (NULL);
854 }
855#ifdef HAVE_STAT
856 len = read(fd, content, size);
857#else
858 len = fread(content, 1, size, fd);
859#endif
860 if (len < 0) {
861 xmlFree(content);
862 return (NULL);
863 }
864#ifdef HAVE_STAT
865 close(fd);
866#else
867 fclose(fd);
868#endif
869 content[len] = 0;
870
871 return(content);
872}
873
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000874/************************************************************************
875 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000876 * The XML Catalog parser *
877 * *
878 ************************************************************************/
879
880static xmlCatalogEntryPtr
881xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000882static void
883xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
884 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000885static xmlChar *
886xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
887 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000888static xmlChar *
889xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
890
Daniel Veillard344cee72001-08-20 00:08:40 +0000891
Daniel Veillard75b96822001-10-11 18:59:45 +0000892/**
893 * xmlGetXMLCatalogEntryType:
894 * @name: the name
895 *
896 * lookup the internal type associated to an XML catalog entry name
897 *
898 * Returns the type associate with that name
899 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000900static xmlCatalogEntryType
901xmlGetXMLCatalogEntryType(const xmlChar *name) {
902 xmlCatalogEntryType type = XML_CATA_NONE;
903 if (xmlStrEqual(name, (const xmlChar *) "system"))
904 type = XML_CATA_SYSTEM;
905 else if (xmlStrEqual(name, (const xmlChar *) "public"))
906 type = XML_CATA_PUBLIC;
907 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
908 type = XML_CATA_REWRITE_SYSTEM;
909 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
910 type = XML_CATA_DELEGATE_PUBLIC;
911 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
912 type = XML_CATA_DELEGATE_SYSTEM;
913 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
914 type = XML_CATA_URI;
915 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
916 type = XML_CATA_REWRITE_URI;
917 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
918 type = XML_CATA_DELEGATE_URI;
919 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
920 type = XML_CATA_NEXT_CATALOG;
921 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
922 type = XML_CATA_CATALOG;
923 return(type);
924}
925
Daniel Veillard75b96822001-10-11 18:59:45 +0000926/**
927 * xmlParseXMLCatalogOneNode:
928 * @cur: the XML node
929 * @type: the type of Catalog entry
930 * @name: the name of the node
931 * @attrName: the attribute holding the value
932 * @uriAttrName: the attribute holding the URI-Reference
933 * @prefer: the PUBLIC vs. SYSTEM current preference value
934 *
935 * Finishes the examination of an XML tree node of a catalog and build
936 * a Catalog entry from it.
937 *
938 * Returns the new Catalog entry node or NULL in case of error.
939 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000940static xmlCatalogEntryPtr
941xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
942 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000943 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000944 int ok = 1;
945 xmlChar *uriValue;
946 xmlChar *nameValue = NULL;
947 xmlChar *base = NULL;
948 xmlChar *URL = NULL;
949 xmlCatalogEntryPtr ret = NULL;
950
951 if (attrName != NULL) {
952 nameValue = xmlGetProp(cur, attrName);
953 if (nameValue == NULL) {
954 xmlGenericError(xmlGenericErrorContext,
955 "%s entry lacks '%s'\n", name, attrName);
956 ok = 0;
957 }
958 }
959 uriValue = xmlGetProp(cur, uriAttrName);
960 if (uriValue == NULL) {
961 xmlGenericError(xmlGenericErrorContext,
962 "%s entry lacks '%s'\n", name, uriAttrName);
963 ok = 0;
964 }
965 if (!ok) {
966 if (nameValue != NULL)
967 xmlFree(nameValue);
968 if (uriValue != NULL)
969 xmlFree(uriValue);
970 return(NULL);
971 }
972
973 base = xmlNodeGetBase(cur->doc, cur);
974 URL = xmlBuildURI(uriValue, base);
975 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000976 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000977 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000978 xmlGenericError(xmlGenericErrorContext,
979 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000980 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000981 xmlGenericError(xmlGenericErrorContext,
982 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000983 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000984 ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000985 } else {
986 xmlGenericError(xmlGenericErrorContext,
987 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
988 }
989 if (nameValue != NULL)
990 xmlFree(nameValue);
991 if (uriValue != NULL)
992 xmlFree(uriValue);
993 if (base != NULL)
994 xmlFree(base);
995 if (URL != NULL)
996 xmlFree(URL);
997 return(ret);
998}
999
Daniel Veillard75b96822001-10-11 18:59:45 +00001000/**
1001 * xmlParseXMLCatalogNode:
1002 * @cur: the XML node
1003 * @prefer: the PUBLIC vs. SYSTEM current preference value
1004 * @parent: the parent Catalog entry
1005 *
1006 * Examines an XML tree node of a catalog and build
1007 * a Catalog entry from it adding it to its parent. The examination can
1008 * be recursive.
1009 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001010static void
1011xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1012 xmlCatalogEntryPtr parent)
1013{
1014 xmlChar *uri = NULL;
1015 xmlChar *URL = NULL;
1016 xmlChar *base = NULL;
1017 xmlCatalogEntryPtr entry = NULL;
1018
1019 if (cur == NULL)
1020 return;
1021 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1022 xmlChar *prop;
1023
1024 prop = xmlGetProp(cur, BAD_CAST "prefer");
1025 if (prop != NULL) {
1026 if (xmlStrEqual(prop, BAD_CAST "system")) {
1027 prefer = XML_CATA_PREFER_SYSTEM;
1028 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1029 prefer = XML_CATA_PREFER_PUBLIC;
1030 } else {
1031 xmlGenericError(xmlGenericErrorContext,
1032 "Invalid value for prefer: '%s'\n", prop);
1033 }
1034 xmlFree(prop);
1035 }
1036 /*
1037 * Recurse to propagate prefer to the subtree
1038 * (xml:base handling is automated)
1039 */
1040 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1041 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1042 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001043 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001044 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1045 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001046 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001047 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1048 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1049 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001050 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001051 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1052 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1053 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001054 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001055 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1056 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1057 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001058 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001059 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1060 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1061 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001062 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001063 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1064 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1065 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001066 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001067 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1068 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1069 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001070 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001071 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1072 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1073 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001074 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001075 }
1076 if ((entry != NULL) && (parent != NULL)) {
1077 entry->parent = parent;
1078 if (parent->children == NULL)
1079 parent->children = entry;
1080 else {
1081 xmlCatalogEntryPtr prev;
1082
1083 prev = parent->children;
1084 while (prev->next != NULL)
1085 prev = prev->next;
1086 prev->next = entry;
1087 }
1088 }
1089 if (base != NULL)
1090 xmlFree(base);
1091 if (uri != NULL)
1092 xmlFree(uri);
1093 if (URL != NULL)
1094 xmlFree(URL);
1095}
1096
Daniel Veillard75b96822001-10-11 18:59:45 +00001097/**
1098 * xmlParseXMLCatalogNodeList:
1099 * @cur: the XML node list of siblings
1100 * @prefer: the PUBLIC vs. SYSTEM current preference value
1101 * @parent: the parent Catalog entry
1102 *
1103 * Examines a list of XML sibling nodes of a catalog and build
1104 * a list of Catalog entry from it adding it to the parent.
1105 * The examination will recurse to examine node subtrees.
1106 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001107static void
1108xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1109 xmlCatalogEntryPtr parent) {
1110 while (cur != NULL) {
1111 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1112 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1113 xmlParseXMLCatalogNode(cur, prefer, parent);
1114 }
1115 cur = cur->next;
1116 }
1117 /* TODO: sort the list according to REWRITE lengths and prefer value */
1118}
1119
Daniel Veillard75b96822001-10-11 18:59:45 +00001120/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001121 * xmlParseXMLCatalogFile:
1122 * @prefer: the PUBLIC vs. SYSTEM current preference value
1123 * @filename: the filename for the catalog
1124 *
1125 * Parses the catalog file to extract the XML tree and then analyze the
1126 * tree to build a list of Catalog entries corresponding to this catalog
1127 *
1128 * Returns the resulting Catalog entries list
1129 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001130static xmlCatalogEntryPtr
1131xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1132 xmlDocPtr doc;
1133 xmlNodePtr cur;
1134 xmlChar *prop;
1135 xmlCatalogEntryPtr parent = NULL;
1136
1137 if (filename == NULL)
1138 return(NULL);
1139
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001140 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001141 if (doc == NULL) {
1142 if (xmlDebugCatalogs)
1143 xmlGenericError(xmlGenericErrorContext,
1144 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001145 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001146 }
1147
1148 if (xmlDebugCatalogs)
1149 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001150 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001151
1152 cur = xmlDocGetRootElement(doc);
1153 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1154 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1155 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1156
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001157 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1158 (const xmlChar *)filename, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001159 if (parent == NULL) {
1160 xmlFreeDoc(doc);
1161 return(NULL);
1162 }
1163
1164 prop = xmlGetProp(cur, BAD_CAST "prefer");
1165 if (prop != NULL) {
1166 if (xmlStrEqual(prop, BAD_CAST "system")) {
1167 prefer = XML_CATA_PREFER_SYSTEM;
1168 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1169 prefer = XML_CATA_PREFER_PUBLIC;
1170 } else {
1171 xmlGenericError(xmlGenericErrorContext,
1172 "Invalid value for prefer: '%s'\n",
1173 prop);
1174 }
1175 xmlFree(prop);
1176 }
1177 cur = cur->children;
1178 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1179 } else {
1180 xmlGenericError(xmlGenericErrorContext,
1181 "File %s is not an XML Catalog\n", filename);
1182 xmlFreeDoc(doc);
1183 return(NULL);
1184 }
1185 xmlFreeDoc(doc);
1186 return(parent);
1187}
1188
Daniel Veillardcda96922001-08-21 10:56:31 +00001189/**
1190 * xmlFetchXMLCatalogFile:
1191 * @catal: an existing but incomplete catalog entry
1192 *
1193 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001194 *
1195 * Returns 0 in case of success, -1 otherwise
1196 */
1197static int
1198xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001199 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001200
1201 if (catal == NULL)
1202 return(-1);
1203 if (catal->value == NULL)
1204 return(-1);
1205 if (catal->children != NULL)
1206 return(-1);
1207
Daniel Veillard81463942001-10-16 12:34:39 +00001208 /*
1209 * lock the whole catalog for modification
1210 */
1211 xmlRMutexLock(xmlCatalogMutex);
1212 if (catal->children != NULL) {
1213 /* Okay someone else did it in the meantime */
1214 xmlRMutexUnlock(xmlCatalogMutex);
1215 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001216 }
1217
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001218 if (xmlCatalogXMLFiles != NULL) {
1219 doc = (xmlCatalogEntryPtr)
Daniel Veillard6990bf32001-08-23 21:17:48 +00001220 xmlHashLookup(xmlCatalogXMLFiles, catal->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001221 if (doc != NULL) {
1222 if (xmlDebugCatalogs)
1223 xmlGenericError(xmlGenericErrorContext,
1224 "Found %s in file hash\n", catal->value);
1225
1226 if (catal->type == XML_CATA_CATALOG)
1227 catal->children = doc->children;
1228 else
1229 catal->children = doc;
1230 catal->dealloc = 0;
1231 xmlRMutexUnlock(xmlCatalogMutex);
1232 return(0);
1233 }
1234 if (xmlDebugCatalogs)
1235 xmlGenericError(xmlGenericErrorContext,
1236 "%s not found in file hash\n", catal->value);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001237 }
1238
Daniel Veillardcda96922001-08-21 10:56:31 +00001239 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001240 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1241 * use the existing catalog, there is no recusivity allowed at
1242 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001243 */
Daniel Veillard6990bf32001-08-23 21:17:48 +00001244 doc = xmlParseXMLCatalogFile(catal->prefer, catal->value);
1245 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001246 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001247 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001248 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001249 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001250
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001251 if (catal->type == XML_CATA_CATALOG)
1252 catal->children = doc->children;
1253 else
1254 catal->children = doc;
1255
1256 doc->dealloc = 1;
1257
Daniel Veillard81463942001-10-16 12:34:39 +00001258 if (xmlCatalogXMLFiles == NULL)
1259 xmlCatalogXMLFiles = xmlHashCreate(10);
1260 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001261 if (xmlDebugCatalogs)
1262 xmlGenericError(xmlGenericErrorContext,
1263 "%s added to file hash\n", catal->value);
1264 xmlHashAddEntry(xmlCatalogXMLFiles, catal->value, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001265 }
Daniel Veillard81463942001-10-16 12:34:39 +00001266 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001267 return(0);
1268}
1269
Daniel Veillard75b96822001-10-11 18:59:45 +00001270/************************************************************************
1271 * *
1272 * XML Catalog handling *
1273 * *
1274 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001275
1276/**
1277 * xmlAddXMLCatalog:
1278 * @catal: top of an XML catalog
1279 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001280 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001281 * @replace: the replacement value for the match
1282 *
1283 * Add an entry in the XML catalog, it may overwrite existing but
1284 * different entries.
1285 *
1286 * Returns 0 if successful, -1 otherwise
1287 */
1288static int
1289xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1290 const xmlChar *orig, const xmlChar *replace) {
1291 xmlCatalogEntryPtr cur;
1292 xmlCatalogEntryType typ;
1293
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001294 if ((catal == NULL) ||
1295 ((catal->type != XML_CATA_CATALOG) &&
1296 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001297 return(-1);
1298 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001299 if (typ == XML_CATA_NONE) {
1300 if (xmlDebugCatalogs)
1301 xmlGenericError(xmlGenericErrorContext,
1302 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001303 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001304 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001305
1306 cur = catal->children;
1307 /*
1308 * Might be a simple "update in place"
1309 */
1310 if (cur != NULL) {
1311 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001312 if ((orig != NULL) && (cur->type == typ) &&
1313 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001314 if (xmlDebugCatalogs)
1315 xmlGenericError(xmlGenericErrorContext,
1316 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001317 if (cur->value != NULL)
1318 xmlFree(cur->value);
1319 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001320 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001321 }
1322 if (cur->next == NULL)
1323 break;
1324 cur = cur->next;
1325 }
1326 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001327 if (xmlDebugCatalogs)
1328 xmlGenericError(xmlGenericErrorContext,
1329 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001330 if (cur == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001331 catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001332 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001333 cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillardcda96922001-08-21 10:56:31 +00001334 return(0);
1335}
1336
1337/**
1338 * xmlDelXMLCatalog:
1339 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001340 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001341 *
1342 * Remove entries in the XML catalog where the value or the URI
1343 * is equal to @value
1344 *
1345 * Returns the number of entries removed if successful, -1 otherwise
1346 */
1347static int
1348xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1349 xmlCatalogEntryPtr cur, prev, tmp;
1350 int ret = 0;
1351
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001352 if ((catal == NULL) ||
1353 ((catal->type != XML_CATA_CATALOG) &&
1354 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001355 return(-1);
1356 if (value == NULL)
1357 return(-1);
1358
1359 /*
1360 * Scan the children
1361 */
1362 cur = catal->children;
1363 prev = NULL;
1364 while (cur != NULL) {
1365 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1366 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001367 if (xmlDebugCatalogs) {
1368 if (cur->name != NULL)
1369 xmlGenericError(xmlGenericErrorContext,
1370 "Removing element %s from catalog\n", cur->name);
1371 else
1372 xmlGenericError(xmlGenericErrorContext,
1373 "Removing element %s from catalog\n", cur->value);
1374 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001375 ret++;
1376 tmp = cur;
1377 cur = tmp->next;
1378 if (prev == NULL) {
1379 catal->children = cur;
1380 } else {
1381 prev->next = cur;
1382 }
1383 xmlFreeCatalogEntry(tmp);
1384 continue;
1385 }
1386 prev = cur;
1387 cur = cur->next;
1388 }
1389 return(ret);
1390}
1391
1392/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001393 * xmlCatalogXMLResolve:
1394 * @catal: a catalog list
1395 * @pubId: the public ID string
1396 * @sysId: the system ID string
1397 *
1398 * Do a complete resolution lookup of an External Identifier for a
1399 * list of catalog entries.
1400 *
1401 * Implements (or tries to) 7.1. External Identifier Resolution
1402 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1403 *
1404 * Returns the URI of the resource or NULL if not found
1405 */
1406static xmlChar *
1407xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1408 const xmlChar *sysID) {
1409 xmlChar *ret = NULL;
1410 xmlCatalogEntryPtr cur;
1411 int haveDelegate = 0;
1412 int haveNext = 0;
1413
1414 /*
1415 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1416 */
1417 if (sysID != NULL) {
1418 xmlCatalogEntryPtr rewrite = NULL;
1419 int lenrewrite = 0, len;
1420 cur = catal;
1421 haveDelegate = 0;
1422 while (cur != NULL) {
1423 switch (cur->type) {
1424 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001425 if (xmlStrEqual(sysID, cur->name)) {
1426 if (xmlDebugCatalogs)
1427 xmlGenericError(xmlGenericErrorContext,
1428 "Found system match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001429 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001430 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001431 break;
1432 case XML_CATA_REWRITE_SYSTEM:
1433 len = xmlStrlen(cur->name);
1434 if ((len > lenrewrite) &&
1435 (!xmlStrncmp(sysID, cur->name, len))) {
1436 lenrewrite = len;
1437 rewrite = cur;
1438 }
1439 break;
1440 case XML_CATA_DELEGATE_SYSTEM:
1441 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1442 haveDelegate++;
1443 break;
1444 case XML_CATA_NEXT_CATALOG:
1445 haveNext++;
1446 break;
1447 default:
1448 break;
1449 }
1450 cur = cur->next;
1451 }
1452 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001453 if (xmlDebugCatalogs)
1454 xmlGenericError(xmlGenericErrorContext,
1455 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001456 ret = xmlStrdup(rewrite->value);
1457 if (ret != NULL)
1458 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1459 return(ret);
1460 }
1461 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001462 const xmlChar *delegates[MAX_DELEGATE];
1463 int nbList = 0, i;
1464
Daniel Veillardcda96922001-08-21 10:56:31 +00001465 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001466 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001467 * matches when the list was produced.
1468 */
1469 cur = catal;
1470 while (cur != NULL) {
1471 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1472 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001473 for (i = 0;i < nbList;i++)
1474 if (xmlStrEqual(cur->value, delegates[i]))
1475 break;
1476 if (i < nbList) {
1477 cur = cur->next;
1478 continue;
1479 }
1480 if (nbList < MAX_DELEGATE)
1481 delegates[nbList++] = cur->value;
1482
Daniel Veillardcda96922001-08-21 10:56:31 +00001483 if (cur->children == NULL) {
1484 xmlFetchXMLCatalogFile(cur);
1485 }
1486 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001487 if (xmlDebugCatalogs)
1488 xmlGenericError(xmlGenericErrorContext,
1489 "Trying system delegate %s\n", cur->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001490 ret = xmlCatalogListXMLResolve(
1491 cur->children, NULL, sysID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001492 if (ret != NULL)
1493 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001494 }
1495 }
1496 cur = cur->next;
1497 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001498 /*
1499 * Apply the cut algorithm explained in 4/
1500 */
1501 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001502 }
1503 }
1504 /*
1505 * Then tries 5/ 6/ if a public ID is provided
1506 */
1507 if (pubID != NULL) {
1508 cur = catal;
1509 haveDelegate = 0;
1510 while (cur != NULL) {
1511 switch (cur->type) {
1512 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001513 if (xmlStrEqual(pubID, cur->name)) {
1514 if (xmlDebugCatalogs)
1515 xmlGenericError(xmlGenericErrorContext,
1516 "Found public match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001517 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001518 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001519 break;
1520 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001521 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1522 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001523 haveDelegate++;
1524 break;
1525 case XML_CATA_NEXT_CATALOG:
1526 if (sysID == NULL)
1527 haveNext++;
1528 break;
1529 default:
1530 break;
1531 }
1532 cur = cur->next;
1533 }
1534 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001535 const xmlChar *delegates[MAX_DELEGATE];
1536 int nbList = 0, i;
1537
Daniel Veillardcda96922001-08-21 10:56:31 +00001538 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001539 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001540 * matches when the list was produced.
1541 */
1542 cur = catal;
1543 while (cur != NULL) {
1544 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001545 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1546 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001547
1548 for (i = 0;i < nbList;i++)
1549 if (xmlStrEqual(cur->value, delegates[i]))
1550 break;
1551 if (i < nbList) {
1552 cur = cur->next;
1553 continue;
1554 }
1555 if (nbList < MAX_DELEGATE)
1556 delegates[nbList++] = cur->value;
1557
Daniel Veillardcda96922001-08-21 10:56:31 +00001558 if (cur->children == NULL) {
1559 xmlFetchXMLCatalogFile(cur);
1560 }
1561 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001562 if (xmlDebugCatalogs)
1563 xmlGenericError(xmlGenericErrorContext,
1564 "Trying public delegate %s\n", cur->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001565 ret = xmlCatalogListXMLResolve(
1566 cur->children, pubID, NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001567 if (ret != NULL)
1568 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001569 }
1570 }
1571 cur = cur->next;
1572 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001573 /*
1574 * Apply the cut algorithm explained in 4/
1575 */
1576 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001577 }
1578 }
1579 if (haveNext) {
1580 cur = catal;
1581 while (cur != NULL) {
1582 if (cur->type == XML_CATA_NEXT_CATALOG) {
1583 if (cur->children == NULL) {
1584 xmlFetchXMLCatalogFile(cur);
1585 }
1586 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001587 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1588 if (ret != NULL)
1589 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001590 }
1591 }
1592 cur = cur->next;
1593 }
1594 }
1595
1596 return(NULL);
1597}
1598
1599/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001600 * xmlCatalogXMLResolveURI:
1601 * @catal: a catalog list
1602 * @URI: the URI
1603 * @sysId: the system ID string
1604 *
1605 * Do a complete resolution lookup of an External Identifier for a
1606 * list of catalog entries.
1607 *
1608 * Implements (or tries to) 7.2.2. URI Resolution
1609 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1610 *
1611 * Returns the URI of the resource or NULL if not found
1612 */
1613static xmlChar *
1614xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1615 xmlChar *ret = NULL;
1616 xmlCatalogEntryPtr cur;
1617 int haveDelegate = 0;
1618 int haveNext = 0;
1619 xmlCatalogEntryPtr rewrite = NULL;
1620 int lenrewrite = 0, len;
1621
1622 if (catal == NULL)
1623 return(NULL);
1624
1625 if (URI == NULL)
1626 return(NULL);
1627
1628 /*
1629 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1630 */
1631 cur = catal;
1632 haveDelegate = 0;
1633 while (cur != NULL) {
1634 switch (cur->type) {
1635 case XML_CATA_URI:
1636 if (xmlStrEqual(URI, cur->name)) {
1637 if (xmlDebugCatalogs)
1638 xmlGenericError(xmlGenericErrorContext,
1639 "Found URI match %s\n", cur->name);
1640 return(xmlStrdup(cur->value));
1641 }
1642 break;
1643 case XML_CATA_REWRITE_URI:
1644 len = xmlStrlen(cur->name);
1645 if ((len > lenrewrite) &&
1646 (!xmlStrncmp(URI, cur->name, len))) {
1647 lenrewrite = len;
1648 rewrite = cur;
1649 }
1650 break;
1651 case XML_CATA_DELEGATE_URI:
1652 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1653 haveDelegate++;
1654 break;
1655 case XML_CATA_NEXT_CATALOG:
1656 haveNext++;
1657 break;
1658 default:
1659 break;
1660 }
1661 cur = cur->next;
1662 }
1663 if (rewrite != NULL) {
1664 if (xmlDebugCatalogs)
1665 xmlGenericError(xmlGenericErrorContext,
1666 "Using rewriting rule %s\n", rewrite->name);
1667 ret = xmlStrdup(rewrite->value);
1668 if (ret != NULL)
1669 ret = xmlStrcat(ret, &URI[lenrewrite]);
1670 return(ret);
1671 }
1672 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001673 const xmlChar *delegates[MAX_DELEGATE];
1674 int nbList = 0, i;
1675
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001676 /*
1677 * Assume the entries have been sorted by decreasing substring
1678 * matches when the list was produced.
1679 */
1680 cur = catal;
1681 while (cur != NULL) {
1682 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1683 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001684 for (i = 0;i < nbList;i++)
1685 if (xmlStrEqual(cur->value, delegates[i]))
1686 break;
1687 if (i < nbList) {
1688 cur = cur->next;
1689 continue;
1690 }
1691 if (nbList < MAX_DELEGATE)
1692 delegates[nbList++] = cur->value;
1693
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001694 if (cur->children == NULL) {
1695 xmlFetchXMLCatalogFile(cur);
1696 }
1697 if (cur->children != NULL) {
1698 if (xmlDebugCatalogs)
1699 xmlGenericError(xmlGenericErrorContext,
1700 "Trying URI delegate %s\n", cur->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001701 ret = xmlCatalogListXMLResolveURI(
1702 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001703 if (ret != NULL)
1704 return(ret);
1705 }
1706 }
1707 cur = cur->next;
1708 }
1709 /*
1710 * Apply the cut algorithm explained in 4/
1711 */
1712 return(XML_CATAL_BREAK);
1713 }
1714 if (haveNext) {
1715 cur = catal;
1716 while (cur != NULL) {
1717 if (cur->type == XML_CATA_NEXT_CATALOG) {
1718 if (cur->children == NULL) {
1719 xmlFetchXMLCatalogFile(cur);
1720 }
1721 if (cur->children != NULL) {
1722 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1723 if (ret != NULL)
1724 return(ret);
1725 }
1726 }
1727 cur = cur->next;
1728 }
1729 }
1730
1731 return(NULL);
1732}
1733
1734/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001735 * xmlCatalogListXMLResolve:
1736 * @catal: a catalog list
1737 * @pubId: the public ID string
1738 * @sysId: the system ID string
1739 *
1740 * Do a complete resolution lookup of an External Identifier for a
1741 * list of catalogs
1742 *
1743 * Implements (or tries to) 7.1. External Identifier Resolution
1744 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1745 *
1746 * Returns the URI of the resource or NULL if not found
1747 */
1748static xmlChar *
1749xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1750 const xmlChar *sysID) {
1751 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001752 xmlChar *urnID = NULL;
1753
1754 if (catal == NULL)
1755 return(NULL);
1756 if ((pubID == NULL) && (sysID == NULL))
1757 return(NULL);
1758
1759 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1760 urnID = xmlCatalogUnWrapURN(pubID);
1761 if (xmlDebugCatalogs) {
1762 if (urnID == NULL)
1763 xmlGenericError(xmlGenericErrorContext,
1764 "Public URN ID %s expanded to NULL\n", pubID);
1765 else
1766 xmlGenericError(xmlGenericErrorContext,
1767 "Public URN ID expanded to %s\n", urnID);
1768 }
1769 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1770 if (urnID != NULL)
1771 xmlFree(urnID);
1772 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001773 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001774 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1775 urnID = xmlCatalogUnWrapURN(sysID);
1776 if (xmlDebugCatalogs) {
1777 if (urnID == NULL)
1778 xmlGenericError(xmlGenericErrorContext,
1779 "System URN ID %s expanded to NULL\n", sysID);
1780 else
1781 xmlGenericError(xmlGenericErrorContext,
1782 "System URN ID expanded to %s\n", urnID);
1783 }
1784 if (pubID == NULL)
1785 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1786 else if (xmlStrEqual(pubID, urnID))
1787 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1788 else {
1789 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1790 }
1791 if (urnID != NULL)
1792 xmlFree(urnID);
1793 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001794 }
1795 while (catal != NULL) {
1796 if (catal->type == XML_CATA_CATALOG) {
1797 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001798 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001799 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001800 if (catal->children != NULL) {
1801 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1802 if (ret != NULL)
1803 return(ret);
1804 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001805 }
1806 catal = catal->next;
1807 }
1808 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001809}
1810
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001811/**
1812 * xmlCatalogListXMLResolveURI:
1813 * @catal: a catalog list
1814 * @URI: the URI
1815 *
1816 * Do a complete resolution lookup of an URI for a list of catalogs
1817 *
1818 * Implements (or tries to) 7.2. URI Resolution
1819 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1820 *
1821 * Returns the URI of the resource or NULL if not found
1822 */
1823static xmlChar *
1824xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1825 xmlChar *ret = NULL;
1826 xmlChar *urnID = NULL;
1827
1828 if (catal == NULL)
1829 return(NULL);
1830 if (URI == NULL)
1831 return(NULL);
1832
1833 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1834 urnID = xmlCatalogUnWrapURN(URI);
1835 if (xmlDebugCatalogs) {
1836 if (urnID == NULL)
1837 xmlGenericError(xmlGenericErrorContext,
1838 "URN ID %s expanded to NULL\n", URI);
1839 else
1840 xmlGenericError(xmlGenericErrorContext,
1841 "URN ID expanded to %s\n", urnID);
1842 }
1843 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1844 if (urnID != NULL)
1845 xmlFree(urnID);
1846 return(ret);
1847 }
1848 while (catal != NULL) {
1849 if (catal->type == XML_CATA_CATALOG) {
1850 if (catal->children == NULL) {
1851 xmlFetchXMLCatalogFile(catal);
1852 }
1853 if (catal->children != NULL) {
1854 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1855 if (ret != NULL)
1856 return(ret);
1857 }
1858 }
1859 catal = catal->next;
1860 }
1861 return(ret);
1862}
1863
Daniel Veillard344cee72001-08-20 00:08:40 +00001864/************************************************************************
1865 * *
1866 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001867 * *
1868 ************************************************************************/
1869
1870
1871#define RAW *cur
1872#define NEXT cur++;
1873#define SKIP(x) cur += x;
1874
1875#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1876
Daniel Veillard75b96822001-10-11 18:59:45 +00001877/**
1878 * xmlParseSGMLCatalogComment:
1879 * @cur: the current character
1880 *
1881 * Skip a comment in an SGML catalog
1882 *
1883 * Returns new current character
1884 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001885static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001886xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001887 if ((cur[0] != '-') || (cur[1] != '-'))
1888 return(cur);
1889 SKIP(2);
1890 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1891 NEXT;
1892 if (cur[0] == 0) {
1893 return(NULL);
1894 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001895 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001896}
1897
Daniel Veillard75b96822001-10-11 18:59:45 +00001898/**
1899 * xmlParseSGMLCatalogPubid:
1900 * @cur: the current character
1901 * @id: the return location
1902 *
1903 * Parse an SGML catalog ID
1904 *
1905 * Returns new current character and store the value in @id
1906 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001907static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001908xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001909 xmlChar *buf = NULL;
1910 int len = 0;
1911 int size = 50;
1912 xmlChar stop;
1913 int count = 0;
1914
1915 *id = NULL;
1916
1917 if (RAW == '"') {
1918 NEXT;
1919 stop = '"';
1920 } else if (RAW == '\'') {
1921 NEXT;
1922 stop = '\'';
1923 } else {
1924 stop = ' ';
1925 }
1926 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1927 if (buf == NULL) {
1928 xmlGenericError(xmlGenericErrorContext,
1929 "malloc of %d byte failed\n", size);
1930 return(NULL);
1931 }
1932 while (xmlIsPubidChar(*cur)) {
1933 if ((*cur == stop) && (stop != ' '))
1934 break;
1935 if ((stop == ' ') && (IS_BLANK(*cur)))
1936 break;
1937 if (len + 1 >= size) {
1938 size *= 2;
1939 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1940 if (buf == NULL) {
1941 xmlGenericError(xmlGenericErrorContext,
1942 "realloc of %d byte failed\n", size);
1943 return(NULL);
1944 }
1945 }
1946 buf[len++] = *cur;
1947 count++;
1948 NEXT;
1949 }
1950 buf[len] = 0;
1951 if (stop == ' ') {
1952 if (!IS_BLANK(*cur)) {
1953 xmlFree(buf);
1954 return(NULL);
1955 }
1956 } else {
1957 if (*cur != stop) {
1958 xmlFree(buf);
1959 return(NULL);
1960 }
1961 NEXT;
1962 }
1963 *id = buf;
1964 return(cur);
1965}
1966
Daniel Veillard75b96822001-10-11 18:59:45 +00001967/**
1968 * xmlParseSGMLCatalogName:
1969 * @cur: the current character
1970 * @name: the return location
1971 *
1972 * Parse an SGML catalog name
1973 *
1974 * Returns new current character and store the value in @name
1975 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001976static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001977xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001978 xmlChar buf[XML_MAX_NAMELEN + 5];
1979 int len = 0;
1980 int c;
1981
1982 *name = NULL;
1983
1984 /*
1985 * Handler for more complex cases
1986 */
1987 c = *cur;
1988 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
1989 return(NULL);
1990 }
1991
1992 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
1993 (c == '.') || (c == '-') ||
1994 (c == '_') || (c == ':'))) {
1995 buf[len++] = c;
1996 cur++;
1997 c = *cur;
1998 if (len >= XML_MAX_NAMELEN)
1999 return(NULL);
2000 }
2001 *name = xmlStrndup(buf, len);
2002 return(cur);
2003}
2004
Daniel Veillard75b96822001-10-11 18:59:45 +00002005/**
2006 * xmlGetSGMLCatalogEntryType:
2007 * @name: the entry name
2008 *
2009 * Get the Catalog entry type for a given SGML Catalog name
2010 *
2011 * Returns Catalog entry type
2012 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002013static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002014xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002015 xmlCatalogEntryType type = XML_CATA_NONE;
2016 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2017 type = SGML_CATA_SYSTEM;
2018 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2019 type = SGML_CATA_PUBLIC;
2020 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2021 type = SGML_CATA_DELEGATE;
2022 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2023 type = SGML_CATA_ENTITY;
2024 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2025 type = SGML_CATA_DOCTYPE;
2026 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2027 type = SGML_CATA_LINKTYPE;
2028 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2029 type = SGML_CATA_NOTATION;
2030 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2031 type = SGML_CATA_SGMLDECL;
2032 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2033 type = SGML_CATA_DOCUMENT;
2034 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2035 type = SGML_CATA_CATALOG;
2036 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2037 type = SGML_CATA_BASE;
2038 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2039 type = SGML_CATA_DELEGATE;
2040 return(type);
2041}
2042
Daniel Veillard75b96822001-10-11 18:59:45 +00002043/**
2044 * xmlParseSGMLCatalog:
2045 * @catal: the SGML Catalog
2046 * @value: the content of the SGML Catalog serialization
2047 * @file: the filepath for the catalog
2048 * @super: should this be handled as a Super Catalog in which case
2049 * parsing is not recursive
2050 *
2051 * Parse an SGML catalog content and fill up the @catal hash table with
2052 * the new entries found.
2053 *
2054 * Returns 0 in case of success, -1 in case of error.
2055 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002056static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002057xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2058 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002059 const xmlChar *cur = value;
2060 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002061 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002062
2063 if ((cur == NULL) || (file == NULL))
2064 return(-1);
2065 base = xmlStrdup((const xmlChar *) file);
2066
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002067 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002068 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002069 if (cur[0] == 0)
2070 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002071 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002072 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002073 if (cur == NULL) {
2074 /* error */
2075 break;
2076 }
2077 } else {
2078 xmlChar *sysid = NULL;
2079 xmlChar *name = NULL;
2080 xmlCatalogEntryType type = XML_CATA_NONE;
2081
Daniel Veillardcda96922001-08-21 10:56:31 +00002082 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002083 if (name == NULL) {
2084 /* error */
2085 break;
2086 }
2087 if (!IS_BLANK(*cur)) {
2088 /* error */
2089 break;
2090 }
2091 SKIP_BLANKS;
2092 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002093 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002094 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002095 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002096 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002097 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002098 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002099 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002100 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002101 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002102 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002103 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002104 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002105 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002106 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002107 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002108 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002109 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002110 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002111 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002112 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002113 type = SGML_CATA_BASE;
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 *) "OVERRIDE")) {
2117 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002118 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002119 if (name == NULL) {
2120 /* error */
2121 break;
2122 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002123 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002124 continue;
2125 }
2126 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002127 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002128
2129 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002130 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002131 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002132 type = SGML_CATA_PENTITY;
2133 case SGML_CATA_PENTITY:
2134 case SGML_CATA_DOCTYPE:
2135 case SGML_CATA_LINKTYPE:
2136 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002137 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002138 if (cur == NULL) {
2139 /* error */
2140 break;
2141 }
2142 if (!IS_BLANK(*cur)) {
2143 /* error */
2144 break;
2145 }
2146 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002147 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002148 if (cur == NULL) {
2149 /* error */
2150 break;
2151 }
2152 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002153 case SGML_CATA_PUBLIC:
2154 case SGML_CATA_SYSTEM:
2155 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002156 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002157 if (cur == NULL) {
2158 /* error */
2159 break;
2160 }
2161 if (!IS_BLANK(*cur)) {
2162 /* error */
2163 break;
2164 }
2165 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002166 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002167 if (cur == NULL) {
2168 /* error */
2169 break;
2170 }
2171 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002172 case SGML_CATA_BASE:
2173 case SGML_CATA_CATALOG:
2174 case SGML_CATA_DOCUMENT:
2175 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002176 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002177 if (cur == NULL) {
2178 /* error */
2179 break;
2180 }
2181 break;
2182 default:
2183 break;
2184 }
2185 if (cur == NULL) {
2186 if (name != NULL)
2187 xmlFree(name);
2188 if (sysid != NULL)
2189 xmlFree(sysid);
2190 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002191 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002192 if (base != NULL)
2193 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002194 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002195 } else if ((type == SGML_CATA_PUBLIC) ||
2196 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002197 xmlChar *filename;
2198
2199 filename = xmlBuildURI(sysid, base);
2200 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002201 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002202
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002203 entry = xmlNewCatalogEntry(type, name, filename,
2204 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002205 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002206 if (res < 0) {
2207 xmlFreeCatalogEntry(entry);
2208 }
2209 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002210 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002211
Daniel Veillard344cee72001-08-20 00:08:40 +00002212 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002213 if (super) {
2214 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002215
Daniel Veillard82d75332001-10-08 15:01:59 +00002216 entry = xmlNewCatalogEntry(type, sysid, NULL,
2217 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002218 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002219 if (res < 0) {
2220 xmlFreeCatalogEntry(entry);
2221 }
2222 } else {
2223 xmlChar *filename;
2224
2225 filename = xmlBuildURI(sysid, base);
2226 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002227 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002228 xmlFree(filename);
2229 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002230 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002231 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002232 /*
2233 * drop anything else we won't handle it
2234 */
2235 if (name != NULL)
2236 xmlFree(name);
2237 if (sysid != NULL)
2238 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002239 }
2240 }
2241 if (base != NULL)
2242 xmlFree(base);
2243 if (cur == NULL)
2244 return(-1);
2245 return(0);
2246}
2247
Daniel Veillard75b96822001-10-11 18:59:45 +00002248/************************************************************************
2249 * *
2250 * SGML Catalog handling *
2251 * *
2252 ************************************************************************/
2253
Daniel Veillardcda96922001-08-21 10:56:31 +00002254/**
2255 * xmlCatalogGetSGMLPublic:
2256 * @catal: an SGML catalog hash
2257 * @pubId: the public ID string
2258 *
2259 * Try to lookup the system ID associated to a public ID
2260 *
2261 * Returns the system ID if found or NULL otherwise.
2262 */
2263static const xmlChar *
2264xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2265 xmlCatalogEntryPtr entry;
2266
2267 if (catal == NULL)
2268 return(NULL);
2269
2270 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2271 if (entry == NULL)
2272 return(NULL);
2273 if (entry->type == SGML_CATA_PUBLIC)
2274 return(entry->value);
2275 return(NULL);
2276}
2277
2278/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002279 * xmlCatalogGetSGMLSystem:
2280 * @catal: an SGML catalog hash
2281 * @sysId: the public ID string
2282 *
2283 * Try to lookup the catalog local reference for a system ID
2284 *
2285 * Returns the system ID if found or NULL otherwise.
2286 */
2287static const xmlChar *
2288xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2289 xmlCatalogEntryPtr entry;
2290
2291 if (catal == NULL)
2292 return(NULL);
2293
2294 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2295 if (entry == NULL)
2296 return(NULL);
2297 if (entry->type == SGML_CATA_SYSTEM)
2298 return(entry->value);
2299 return(NULL);
2300}
2301
2302/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002303 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002304 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002305 * @pubId: the public ID string
2306 * @sysId: the system ID string
2307 *
2308 * Do a complete resolution lookup of an External Identifier
2309 *
2310 * Returns the URI of the resource or NULL if not found
2311 */
2312static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002313xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2314 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002315 const xmlChar *ret = NULL;
2316
Daniel Veillard75b96822001-10-11 18:59:45 +00002317 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002318 return(NULL);
2319
2320 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002321 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002322 if (ret != NULL)
2323 return(ret);
2324 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002325 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002326 return(NULL);
2327}
2328
Daniel Veillarda7374592001-05-10 14:17:55 +00002329/************************************************************************
2330 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002331 * Specific Public interfaces *
2332 * *
2333 ************************************************************************/
2334
2335/**
2336 * xmlLoadSGMLSuperCatalog:
2337 * @filename: a file path
2338 *
2339 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2340 * references. This is only needed for manipulating SGML Super Catalogs
2341 * like adding and removing CATALOG or DELEGATE entries.
2342 *
2343 * Returns the catalog parsed or NULL in case of error
2344 */
2345xmlCatalogPtr
2346xmlLoadSGMLSuperCatalog(const char *filename)
2347{
2348 xmlChar *content;
2349 xmlCatalogPtr catal;
2350 int ret;
2351
2352 content = xmlLoadFileContent(filename);
2353 if (content == NULL)
2354 return(NULL);
2355
2356 catal = xmlNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2357 if (catal == NULL) {
2358 xmlFree(content);
2359 return(NULL);
2360 }
2361
2362 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2363 xmlFree(content);
2364 if (ret < 0) {
2365 xmlFreeCatalog(catal);
2366 return(NULL);
2367 }
2368 return (catal);
2369}
2370
2371/**
2372 * xmlLoadACatalog:
2373 * @filename: a file path
2374 *
2375 * Load the catalog and build the associated data structures.
2376 * This can be either an XML Catalog or an SGML Catalog
2377 * It will recurse in SGML CATALOG entries. On the other hand XML
2378 * Catalogs are not handled recursively.
2379 *
2380 * Returns the catalog parsed or NULL in case of error
2381 */
2382xmlCatalogPtr
2383xmlLoadACatalog(const char *filename)
2384{
2385 xmlChar *content;
2386 xmlChar *first;
2387 xmlCatalogPtr catal;
2388 int ret;
2389
2390 content = xmlLoadFileContent(filename);
2391 if (content == NULL)
2392 return(NULL);
2393
2394
2395 first = content;
2396
2397 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2398 (!(((*first >= 'A') && (*first <= 'Z')) ||
2399 ((*first >= 'a') && (*first <= 'z')))))
2400 first++;
2401
2402 if (*first != '<') {
2403 catal = xmlNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2404 if (catal == NULL) {
2405 xmlFree(content);
2406 return(NULL);
2407 }
2408 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2409 if (ret < 0) {
2410 xmlFreeCatalog(catal);
2411 xmlFree(content);
2412 return(NULL);
2413 }
2414 } else {
2415 catal = xmlNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2416 if (catal == NULL) {
2417 xmlFree(content);
2418 return(NULL);
2419 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002420 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG,
2421 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002422 }
2423 xmlFree(content);
2424 return (catal);
2425}
2426
2427/**
2428 * xmlExpandCatalog:
2429 * @catal: a catalog
2430 * @filename: a file path
2431 *
2432 * Load the catalog and expand the existing catal structure.
2433 * This can be either an XML Catalog or an SGML Catalog
2434 *
2435 * Returns 0 in case of success, -1 in case of error
2436 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002437static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002438xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2439{
Daniel Veillard75b96822001-10-11 18:59:45 +00002440 int ret;
2441
2442 if ((catal == NULL) || (filename == NULL))
2443 return(-1);
2444
Daniel Veillard75b96822001-10-11 18:59:45 +00002445
2446 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002447 xmlChar *content;
2448
2449 content = xmlLoadFileContent(filename);
2450 if (content == NULL)
2451 return(-1);
2452
Daniel Veillard75b96822001-10-11 18:59:45 +00002453 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2454 if (ret < 0) {
2455 xmlFree(content);
2456 return(-1);
2457 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002458 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002459 } else {
2460 xmlCatalogEntryPtr tmp, cur;
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002461 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG,
2462 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002463
Daniel Veillard75b96822001-10-11 18:59:45 +00002464 cur = catal->xml;
2465 if (cur == NULL) {
2466 catal->xml = tmp;
2467 } else {
2468 while (cur->next != NULL) cur = cur->next;
2469 cur->next = tmp;
2470 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002471 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002472 return (0);
2473}
2474
2475/**
2476 * xmlACatalogResolveSystem:
2477 * @catal: a Catalog
2478 * @sysId: the public ID string
2479 *
2480 * Try to lookup the catalog resource for a system ID
2481 *
2482 * Returns the system ID if found or NULL otherwise, the value returned
2483 * must be freed by the caller.
2484 */
2485xmlChar *
2486xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2487 xmlChar *ret = NULL;
2488
2489 if ((sysID == NULL) || (catal == NULL))
2490 return(NULL);
2491
2492 if (xmlDebugCatalogs)
2493 xmlGenericError(xmlGenericErrorContext,
2494 "Resolve sysID %s\n", sysID);
2495
2496 if (catal->type == XML_XML_CATALOG_TYPE) {
2497 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2498 if (ret == XML_CATAL_BREAK)
2499 ret = NULL;
2500 } else {
2501 const xmlChar *sgml;
2502
2503 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2504 if (sgml != NULL)
2505 ret = xmlStrdup(sgml);
2506 }
2507 return(ret);
2508}
2509
2510/**
2511 * xmlACatalogResolvePublic:
2512 * @catal: a Catalog
2513 * @pubId: the public ID string
2514 *
2515 * Try to lookup the system ID associated to a public ID in that catalog
2516 *
2517 * Returns the system ID if found or NULL otherwise, the value returned
2518 * must be freed by the caller.
2519 */
2520xmlChar *
2521xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2522 xmlChar *ret = NULL;
2523
2524 if ((pubID == NULL) || (catal == NULL))
2525 return(NULL);
2526
2527 if (xmlDebugCatalogs)
2528 xmlGenericError(xmlGenericErrorContext,
2529 "Resolve pubID %s\n", pubID);
2530
2531 if (catal->type == XML_XML_CATALOG_TYPE) {
2532 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2533 if (ret == XML_CATAL_BREAK)
2534 ret = NULL;
2535 } else {
2536 const xmlChar *sgml;
2537
2538 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2539 if (sgml != NULL)
2540 ret = xmlStrdup(sgml);
2541 }
2542 return(ret);
2543}
2544
2545/**
2546 * xmlACatalogResolve:
2547 * @catal: a Catalog
2548 * @pubId: the public ID string
2549 * @sysId: the system ID string
2550 *
2551 * Do a complete resolution lookup of an External Identifier
2552 *
2553 * Returns the URI of the resource or NULL if not found, it must be freed
2554 * by the caller.
2555 */
2556xmlChar *
2557xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2558 const xmlChar * sysID)
2559{
2560 xmlChar *ret = NULL;
2561
2562 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2563 return (NULL);
2564
2565 if (xmlDebugCatalogs) {
2566 if (pubID != NULL) {
2567 xmlGenericError(xmlGenericErrorContext,
2568 "Resolve: pubID %s\n", pubID);
2569 } else {
2570 xmlGenericError(xmlGenericErrorContext,
2571 "Resolve: sysID %s\n", sysID);
2572 }
2573 }
2574
2575 if (catal->type == XML_XML_CATALOG_TYPE) {
2576 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2577 if (ret == XML_CATAL_BREAK)
2578 ret = NULL;
2579 } else {
2580 const xmlChar *sgml;
2581
2582 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2583 if (sgml != NULL)
2584 ret = xmlStrdup(sgml);
2585 }
2586 return (ret);
2587}
2588
2589/**
2590 * xmlACatalogResolveURI:
2591 * @catal: a Catalog
2592 * @pubId: the URI
2593 *
2594 * Do a complete resolution lookup of an URI
2595 *
2596 * Returns the URI of the resource or NULL if not found, it must be freed
2597 * by the caller.
2598 */
2599xmlChar *
2600xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2601 xmlChar *ret = NULL;
2602
2603 if ((URI == NULL) || (catal == NULL))
2604 return(NULL);
2605
Daniel Veillardb44025c2001-10-11 22:55:55 +00002606 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002607 xmlGenericError(xmlGenericErrorContext,
2608 "Resolve URI %s\n", URI);
2609
2610 if (catal->type == XML_XML_CATALOG_TYPE) {
2611 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2612 if (ret == XML_CATAL_BREAK)
2613 ret = NULL;
2614 } else {
2615 const xmlChar *sgml;
2616
2617 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2618 if (sgml != NULL)
2619 sgml = xmlStrdup(sgml);
2620 }
2621 return(ret);
2622}
2623
2624/**
2625 * xmlACatalogDump:
2626 * @catal: a Catalog
2627 * @out: the file.
2628 *
2629 * Free up all the memory associated with catalogs
2630 */
2631void
2632xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
2633 if (out == NULL)
2634 return;
2635
2636 if (catal->type == XML_XML_CATALOG_TYPE) {
2637 xmlDumpXMLCatalog(out, catal->xml);
2638 } else {
2639 xmlHashScan(catal->sgml,
2640 (xmlHashScanner) xmlCatalogDumpEntry, out);
2641 }
2642}
2643
2644/**
2645 * xmlACatalogAdd:
2646 * @catal: a Catalog
2647 * @type: the type of record to add to the catalog
2648 * @orig: the system, public or prefix to match
2649 * @replace: the replacement value for the match
2650 *
2651 * Add an entry in the catalog, it may overwrite existing but
2652 * different entries.
2653 *
2654 * Returns 0 if successful, -1 otherwise
2655 */
2656int
2657xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2658 const xmlChar * orig, const xmlChar * replace)
2659{
2660 int res = -1;
2661
2662 if (catal == NULL)
2663 return(-1);
2664
2665 if (catal->type == XML_XML_CATALOG_TYPE) {
2666 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2667 } else {
2668 xmlCatalogEntryType cattype;
2669
2670 cattype = xmlGetSGMLCatalogEntryType(type);
2671 if (cattype != XML_CATA_NONE) {
2672 xmlCatalogEntryPtr entry;
2673
2674 entry = xmlNewCatalogEntry(cattype, orig, replace,
2675 XML_CATA_PREFER_NONE);
2676 res = xmlHashAddEntry(catal->sgml, orig, entry);
2677 }
2678 }
2679 return (res);
2680}
2681
2682/**
2683 * xmlACatalogRemove:
2684 * @catal: a Catalog
2685 * @value: the value to remove
2686 *
2687 * Remove an entry from the catalog
2688 *
2689 * Returns the number of entries removed if successful, -1 otherwise
2690 */
2691int
2692xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2693 int res = -1;
2694
2695 if ((catal == NULL) || (value == NULL))
2696 return(-1);
2697
2698 if (catal->type == XML_XML_CATALOG_TYPE) {
2699 res = xmlDelXMLCatalog(catal->xml, value);
2700 } else {
2701 res = xmlHashRemoveEntry(catal->sgml, value,
2702 (xmlHashDeallocator) xmlFreeCatalogEntry);
2703 if (res == 0)
2704 res = 1;
2705 }
2706 return(res);
2707}
2708
2709/************************************************************************
2710 * *
2711 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002712 * *
2713 ************************************************************************/
2714
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002715/**
Daniel Veillard81463942001-10-16 12:34:39 +00002716 * xmlInitializeCatalogData:
2717 *
2718 * Do the catalog initialization only of global data, doesn't try to load
2719 * any catalog actually.
2720 * this function is not thread safe, catalog initialization should
2721 * preferably be done once at startup
2722 */
2723static void
2724xmlInitializeCatalogData(void) {
2725 if (xmlCatalogInitialized != 0)
2726 return;
2727
2728 if (getenv("XML_DEBUG_CATALOG"))
2729 xmlDebugCatalogs = 1;
2730 xmlCatalogMutex = xmlNewRMutex();
2731
2732 xmlCatalogInitialized = 1;
2733}
2734/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002735 * xmlInitializeCatalog:
2736 *
2737 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002738 * this function is not thread safe, catalog initialization should
2739 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002740 */
2741void
2742xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002743 if (xmlCatalogInitialized != 0)
2744 return;
2745
Daniel Veillard81463942001-10-16 12:34:39 +00002746 xmlInitializeCatalogData();
2747 xmlRMutexLock(xmlCatalogMutex);
2748
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002749 if (getenv("XML_DEBUG_CATALOG"))
2750 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002751
Daniel Veillard75b96822001-10-11 18:59:45 +00002752 if (xmlDefaultCatalog == NULL) {
2753 const char *catalogs;
2754 xmlCatalogPtr catal;
2755
Daniel Veillardb44025c2001-10-11 22:55:55 +00002756 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002757 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002758 catalogs = XML_XML_DEFAULT_CATALOG;
2759
2760 catal = xmlNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002761 if (catal != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002762
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002763 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002764 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002765
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002766 xmlDefaultCatalog = catal;
2767 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002768 }
2769
Daniel Veillard81463942001-10-16 12:34:39 +00002770 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002771}
2772
Daniel Veillard82d75332001-10-08 15:01:59 +00002773
2774/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002775 * xmlLoadCatalog:
2776 * @filename: a file path
2777 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002778 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002779 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002780 * this function is not thread safe, catalog initialization should
2781 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002782 *
2783 * Returns 0 in case of success -1 in case of error
2784 */
2785int
Daniel Veillard16756b62001-10-01 07:36:25 +00002786xmlLoadCatalog(const char *filename)
2787{
Daniel Veillard75b96822001-10-11 18:59:45 +00002788 int ret;
2789 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002790
Daniel Veillard81463942001-10-16 12:34:39 +00002791 if (!xmlCatalogInitialized)
2792 xmlInitializeCatalogData();
2793
2794 xmlRMutexLock(xmlCatalogMutex);
2795
Daniel Veillard75b96822001-10-11 18:59:45 +00002796 if (xmlDefaultCatalog == NULL) {
2797 catal = xmlLoadACatalog(filename);
2798 if (catal == NULL)
2799 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002800
Daniel Veillard75b96822001-10-11 18:59:45 +00002801 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002802 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002803 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002804 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002805
Daniel Veillard75b96822001-10-11 18:59:45 +00002806 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002807 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002808 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002809}
2810
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002811/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002812 * xmlLoadCatalogs:
2813 * @paths: a list of file path separated by ':' or spaces
2814 *
2815 * Load the catalogs and makes their definitions effective for the default
2816 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002817 * this function is not thread safe, catalog initialization should
2818 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002819 */
2820void
2821xmlLoadCatalogs(const char *pathss) {
2822 const char *cur;
2823 const char *paths;
2824 xmlChar *path;
2825
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002826 if (pathss == NULL)
2827 return;
2828
Daniel Veillard81418e32001-05-22 15:08:55 +00002829 cur = pathss;
2830 while ((cur != NULL) && (*cur != 0)) {
2831 while (IS_BLANK(*cur)) cur++;
2832 if (*cur != 0) {
2833 paths = cur;
2834 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2835 cur++;
2836 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2837 if (path != NULL) {
2838 xmlLoadCatalog((const char *) path);
2839 xmlFree(path);
2840 }
2841 }
2842 while (*cur == ':')
2843 cur++;
2844 }
2845}
2846
Daniel Veillarda7374592001-05-10 14:17:55 +00002847/**
2848 * xmlCatalogCleanup:
2849 *
2850 * Free up all the memory associated with catalogs
2851 */
2852void
2853xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00002854 if (xmlCatalogInitialized == 0)
2855 return;
2856
Daniel Veillard81463942001-10-16 12:34:39 +00002857 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002858 if (xmlDebugCatalogs)
2859 xmlGenericError(xmlGenericErrorContext,
2860 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002861 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002862 xmlHashFree(xmlCatalogXMLFiles,
2863 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002864 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002865 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002866 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002867 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002868 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002869 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00002870 xmlRMutexUnlock(xmlCatalogMutex);
2871 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00002872}
2873
2874/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002875 * xmlCatalogResolveSystem:
2876 * @sysId: the public ID string
2877 *
2878 * Try to lookup the catalog resource for a system ID
2879 *
2880 * Returns the system ID if found or NULL otherwise, the value returned
2881 * must be freed by the caller.
2882 */
2883xmlChar *
2884xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002885 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002886
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002887 if (!xmlCatalogInitialized)
2888 xmlInitializeCatalog();
2889
Daniel Veillard75b96822001-10-11 18:59:45 +00002890 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
2891 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002892}
2893
2894/**
2895 * xmlCatalogResolvePublic:
2896 * @pubId: the public ID string
2897 *
2898 * Try to lookup the system ID associated to a public ID
2899 *
2900 * Returns the system ID if found or NULL otherwise, the value returned
2901 * must be freed by the caller.
2902 */
2903xmlChar *
2904xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002905 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002906
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002907 if (!xmlCatalogInitialized)
2908 xmlInitializeCatalog();
2909
Daniel Veillard75b96822001-10-11 18:59:45 +00002910 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
2911 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002912}
Daniel Veillard344cee72001-08-20 00:08:40 +00002913
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002914/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002915 * xmlCatalogResolve:
2916 * @pubId: the public ID string
2917 * @sysId: the system ID string
2918 *
2919 * Do a complete resolution lookup of an External Identifier
2920 *
2921 * Returns the URI of the resource or NULL if not found, it must be freed
2922 * by the caller.
2923 */
2924xmlChar *
2925xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002926 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002927
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002928 if (!xmlCatalogInitialized)
2929 xmlInitializeCatalog();
2930
Daniel Veillard75b96822001-10-11 18:59:45 +00002931 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
2932 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002933}
2934
2935/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002936 * xmlCatalogResolveURI:
2937 * @pubId: the URI
2938 *
2939 * Do a complete resolution lookup of an URI
2940 *
2941 * Returns the URI of the resource or NULL if not found, it must be freed
2942 * by the caller.
2943 */
2944xmlChar *
2945xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002946 xmlChar *ret;
2947
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002948 if (!xmlCatalogInitialized)
2949 xmlInitializeCatalog();
2950
Daniel Veillard75b96822001-10-11 18:59:45 +00002951 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
2952 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002953}
2954
2955/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002956 * xmlCatalogDump:
2957 * @out: the file.
2958 *
2959 * Free up all the memory associated with catalogs
2960 */
2961void
2962xmlCatalogDump(FILE *out) {
2963 if (out == NULL)
2964 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00002965
Daniel Veillard75b96822001-10-11 18:59:45 +00002966 if (!xmlCatalogInitialized)
2967 xmlInitializeCatalog();
2968
2969 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00002970}
2971
2972/**
2973 * xmlCatalogAdd:
2974 * @type: the type of record to add to the catalog
2975 * @orig: the system, public or prefix to match
2976 * @replace: the replacement value for the match
2977 *
2978 * Add an entry in the catalog, it may overwrite existing but
2979 * different entries.
Daniel Veillard75b96822001-10-11 18:59:45 +00002980 * If called before any other catalo routine, allows to override the
2981 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00002982 *
2983 * Returns 0 if successful, -1 otherwise
2984 */
2985int
2986xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
2987 int res = -1;
2988
Daniel Veillard81463942001-10-16 12:34:39 +00002989 if (!xmlCatalogInitialized)
2990 xmlInitializeCatalogData();
2991
2992 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002993 /*
2994 * Specific case where one want to override the default catalog
2995 * put in place by xmlInitializeCatalog();
2996 */
2997 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00002998 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002999 xmlDefaultCatalog = xmlNewCatalog(XML_XML_CATALOG_TYPE,
3000 xmlCatalogDefaultPrefer);
3001 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3002 orig, xmlCatalogDefaultPrefer);
3003
Daniel Veillard81463942001-10-16 12:34:39 +00003004 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003005 return(0);
3006 }
3007
Daniel Veillard75b96822001-10-11 18:59:45 +00003008 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003009 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003010 return(res);
3011}
3012
3013/**
3014 * xmlCatalogRemove:
3015 * @value: the value to remove
3016 *
3017 * Remove an entry from the catalog
3018 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003019 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003020 */
3021int
3022xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003023 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003024
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003025 if (!xmlCatalogInitialized)
3026 xmlInitializeCatalog();
3027
Daniel Veillard81463942001-10-16 12:34:39 +00003028 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003029 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003030 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003031 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003032}
3033
3034/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003035 * xmlCatalogConvert:
3036 *
3037 * Convert all the SGML catalog entries as XML ones
3038 *
3039 * Returns the number of entries converted if successful, -1 otherwise
3040 */
3041int
3042xmlCatalogConvert(void) {
3043 int res = -1;
3044
3045 if (!xmlCatalogInitialized)
3046 xmlInitializeCatalog();
3047
Daniel Veillard81463942001-10-16 12:34:39 +00003048 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003049 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003050 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003051 return(res);
3052}
3053
Daniel Veillard75b96822001-10-11 18:59:45 +00003054/************************************************************************
3055 * *
3056 * Public interface manipulating the common preferences *
3057 * *
3058 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003059
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003060/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003061 * xmlCatalogGetDefaults:
3062 *
3063 * Used to get the user preference w.r.t. to what catalogs should
3064 * be accepted
3065 *
3066 * Returns the current xmlCatalogAllow value
3067 */
3068xmlCatalogAllow
3069xmlCatalogGetDefaults(void) {
3070 return(xmlCatalogDefaultAllow);
3071}
3072
3073/**
3074 * xmlCatalogSetDefaults:
3075 *
3076 * Used to set the user preference w.r.t. to what catalogs should
3077 * be accepted
3078 */
3079void
3080xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003081 if (xmlDebugCatalogs) {
3082 switch (allow) {
3083 case XML_CATA_ALLOW_NONE:
3084 xmlGenericError(xmlGenericErrorContext,
3085 "Disabling catalog usage\n");
3086 break;
3087 case XML_CATA_ALLOW_GLOBAL:
3088 xmlGenericError(xmlGenericErrorContext,
3089 "Allowing only global catalogs\n");
3090 break;
3091 case XML_CATA_ALLOW_DOCUMENT:
3092 xmlGenericError(xmlGenericErrorContext,
3093 "Allowing only catalogs from the document\n");
3094 break;
3095 case XML_CATA_ALLOW_ALL:
3096 xmlGenericError(xmlGenericErrorContext,
3097 "Allowing all catalogs\n");
3098 break;
3099 }
3100 }
3101 xmlCatalogDefaultAllow = allow;
3102}
3103
3104/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003105 * xmlCatalogSetDefaultPrefer:
3106 * @prefer: the default preference for delegation
3107 *
3108 * Allows to set the preference between public and system for deletion
3109 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003110 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003111 *
3112 * Returns the previous value of the default preference for delegation
3113 */
3114xmlCatalogPrefer
3115xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3116 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3117
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003118 if (prefer == XML_CATA_PREFER_NONE)
3119 return(ret);
3120
3121 if (xmlDebugCatalogs) {
3122 switch (prefer) {
3123 case XML_CATA_PREFER_PUBLIC:
3124 xmlGenericError(xmlGenericErrorContext,
3125 "Setting catalog preference to PUBLIC\n");
3126 break;
3127 case XML_CATA_PREFER_SYSTEM:
3128 xmlGenericError(xmlGenericErrorContext,
3129 "Setting catalog preference to SYSTEM\n");
3130 break;
3131 case XML_CATA_PREFER_NONE:
3132 break;
3133 }
3134 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003135 xmlCatalogDefaultPrefer = prefer;
3136 return(ret);
3137}
3138
3139/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003140 * xmlCatalogSetDebug:
3141 * @level: the debug level of catalogs required
3142 *
3143 * Used to set the debug level for catalog operation, 0 disable
3144 * debugging, 1 enable it
3145 *
3146 * Returns the previous value of the catalog debugging level
3147 */
3148int
3149xmlCatalogSetDebug(int level) {
3150 int ret = xmlDebugCatalogs;
3151
3152 if (level <= 0)
3153 xmlDebugCatalogs = 0;
3154 else
3155 xmlDebugCatalogs = level;
3156 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003157}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003158
Daniel Veillard75b96822001-10-11 18:59:45 +00003159/************************************************************************
3160 * *
3161 * Minimal interfaces used for per-document catalogs by the parser *
3162 * *
3163 ************************************************************************/
3164
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003165/**
3166 * xmlCatalogFreeLocal:
3167 * @catalogs: a document's list of catalogs
3168 *
3169 * Free up the memory associated to the catalog list
3170 */
3171void
3172xmlCatalogFreeLocal(void *catalogs) {
3173 xmlCatalogEntryPtr catal;
3174
Daniel Veillard81463942001-10-16 12:34:39 +00003175 if (!xmlCatalogInitialized)
3176 xmlInitializeCatalog();
3177
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003178 catal = (xmlCatalogEntryPtr) catalogs;
3179 if (catal != NULL)
3180 xmlFreeCatalogEntryList(catal);
3181}
3182
3183
3184/**
3185 * xmlCatalogAddLocal:
3186 * @catalogs: a document's list of catalogs
3187 * @URL: the URL to a new local catalog
3188 *
3189 * Add the new entry to the catalog list
3190 *
3191 * Returns the updated list
3192 */
3193void *
3194xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3195 xmlCatalogEntryPtr catal, add;
3196
3197 if (!xmlCatalogInitialized)
3198 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003199
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003200 if (URL == NULL)
3201 return(catalogs);
3202
3203 if (xmlDebugCatalogs)
3204 xmlGenericError(xmlGenericErrorContext,
3205 "Adding document catalog %s\n", URL);
3206
3207 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
3208 xmlCatalogDefaultPrefer);
3209 if (add == NULL)
3210 return(catalogs);
3211
3212 catal = (xmlCatalogEntryPtr) catalogs;
3213 if (catal == NULL)
3214 return((void *) add);
3215
3216 while (catal->next != NULL)
3217 catal = catal->next;
3218 catal->next = add;
3219 return(catalogs);
3220}
3221
3222/**
3223 * xmlCatalogLocalResolve:
3224 * @catalogs: a document's list of catalogs
3225 * @pubId: the public ID string
3226 * @sysId: the system ID string
3227 *
3228 * Do a complete resolution lookup of an External Identifier using a
3229 * document's private catalog list
3230 *
3231 * Returns the URI of the resource or NULL if not found, it must be freed
3232 * by the caller.
3233 */
3234xmlChar *
3235xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3236 const xmlChar *sysID) {
3237 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003238 xmlChar *ret;
3239
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003240 if (!xmlCatalogInitialized)
3241 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003242
Daniel Veillard81463942001-10-16 12:34:39 +00003243 if ((pubID == NULL) && (sysID == NULL))
3244 return(NULL);
3245
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003246 if (xmlDebugCatalogs) {
3247 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003248 xmlGenericError(xmlGenericErrorContext,
3249 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003250 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003251 xmlGenericError(xmlGenericErrorContext,
3252 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003253 }
3254 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003255
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003256 catal = (xmlCatalogEntryPtr) catalogs;
3257 if (catal == NULL)
3258 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003259 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3260 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3261 return(ret);
3262 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003263}
3264
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003265/**
3266 * xmlCatalogLocalResolveURI:
3267 * @catalogs: a document's list of catalogs
3268 * @pubId: the URI
3269 *
3270 * Do a complete resolution lookup of an URI using a
3271 * document's private catalog list
3272 *
3273 * Returns the URI of the resource or NULL if not found, it must be freed
3274 * by the caller.
3275 */
3276xmlChar *
3277xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3278 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003279 xmlChar *ret;
3280
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003281 if (!xmlCatalogInitialized)
3282 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003283
Daniel Veillard81463942001-10-16 12:34:39 +00003284 if (URI == NULL)
3285 return(NULL);
3286
Daniel Veillard6990bf32001-08-23 21:17:48 +00003287 if (xmlDebugCatalogs)
3288 xmlGenericError(xmlGenericErrorContext,
3289 "Resolve URI %s\n", URI);
3290
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003291 catal = (xmlCatalogEntryPtr) catalogs;
3292 if (catal == NULL)
3293 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003294 ret = xmlCatalogListXMLResolveURI(catal, URI);
3295 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3296 return(ret);
3297 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003298}
3299
Daniel Veillard75b96822001-10-11 18:59:45 +00003300/************************************************************************
3301 * *
3302 * Deprecated interfaces *
3303 * *
3304 ************************************************************************/
3305/**
3306 * xmlCatalogGetSystem:
3307 * @pubId: the public ID string
3308 *
3309 * Try to lookup the system ID associated to a public ID
3310 * DEPRECATED, use xmlCatalogResolveSystem()
3311 *
3312 * Returns the system ID if found or NULL otherwise.
3313 */
3314const xmlChar *
3315xmlCatalogGetSystem(const xmlChar *sysID) {
3316 xmlChar *ret;
3317 static xmlChar result[1000];
3318 static int msg = 0;
3319
Daniel Veillard81463942001-10-16 12:34:39 +00003320 if (!xmlCatalogInitialized)
3321 xmlInitializeCatalog();
3322
Daniel Veillard75b96822001-10-11 18:59:45 +00003323 if (msg == 0) {
3324 xmlGenericError(xmlGenericErrorContext,
3325 "Use of deprecated xmlCatalogGetSystem() call\n");
3326 msg++;
3327 }
3328
3329 if (sysID == NULL)
3330 return(NULL);
3331
Daniel Veillard75b96822001-10-11 18:59:45 +00003332 /*
3333 * Check first the XML catalogs
3334 */
3335 if (xmlDefaultCatalog != NULL) {
3336 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3337 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3338 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3339 result[sizeof(result) - 1] = 0;
3340 return(result);
3341 }
3342 }
3343
3344 if (xmlDefaultCatalog != NULL)
3345 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3346 return(NULL);
3347}
3348
3349/**
3350 * xmlCatalogGetPublic:
3351 * @pubId: the public ID string
3352 *
3353 * Try to lookup the system ID associated to a public ID
3354 * DEPRECATED, use xmlCatalogResolvePublic()
3355 *
3356 * Returns the system ID if found or NULL otherwise.
3357 */
3358const xmlChar *
3359xmlCatalogGetPublic(const xmlChar *pubID) {
3360 xmlChar *ret;
3361 static xmlChar result[1000];
3362 static int msg = 0;
3363
Daniel Veillard81463942001-10-16 12:34:39 +00003364 if (!xmlCatalogInitialized)
3365 xmlInitializeCatalog();
3366
Daniel Veillard75b96822001-10-11 18:59:45 +00003367 if (msg == 0) {
3368 xmlGenericError(xmlGenericErrorContext,
3369 "Use of deprecated xmlCatalogGetPublic() call\n");
3370 msg++;
3371 }
3372
3373 if (pubID == NULL)
3374 return(NULL);
3375
Daniel Veillard75b96822001-10-11 18:59:45 +00003376 /*
3377 * Check first the XML catalogs
3378 */
3379 if (xmlDefaultCatalog != NULL) {
3380 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3381 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3382 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3383 result[sizeof(result) - 1] = 0;
3384 return(result);
3385 }
3386 }
3387
3388 if (xmlDefaultCatalog != NULL)
3389 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3390 return(NULL);
3391}
3392
Daniel Veillarda7374592001-05-10 14:17:55 +00003393#endif /* LIBXML_CATALOG_ENABLED */