blob: 40e91a57a7356f1f0b7fe8c53380e2c1291d0c20 [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 xmlCatalogEntryPtr
883xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
884 const char *file);
885static void
886xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
887 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000888static xmlChar *
889xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
890 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000891static xmlChar *
892xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
893
Daniel Veillard344cee72001-08-20 00:08:40 +0000894
Daniel Veillard75b96822001-10-11 18:59:45 +0000895/**
896 * xmlGetXMLCatalogEntryType:
897 * @name: the name
898 *
899 * lookup the internal type associated to an XML catalog entry name
900 *
901 * Returns the type associate with that name
902 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000903static xmlCatalogEntryType
904xmlGetXMLCatalogEntryType(const xmlChar *name) {
905 xmlCatalogEntryType type = XML_CATA_NONE;
906 if (xmlStrEqual(name, (const xmlChar *) "system"))
907 type = XML_CATA_SYSTEM;
908 else if (xmlStrEqual(name, (const xmlChar *) "public"))
909 type = XML_CATA_PUBLIC;
910 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
911 type = XML_CATA_REWRITE_SYSTEM;
912 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
913 type = XML_CATA_DELEGATE_PUBLIC;
914 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
915 type = XML_CATA_DELEGATE_SYSTEM;
916 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
917 type = XML_CATA_URI;
918 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
919 type = XML_CATA_REWRITE_URI;
920 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
921 type = XML_CATA_DELEGATE_URI;
922 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
923 type = XML_CATA_NEXT_CATALOG;
924 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
925 type = XML_CATA_CATALOG;
926 return(type);
927}
928
Daniel Veillard75b96822001-10-11 18:59:45 +0000929/**
930 * xmlParseXMLCatalogOneNode:
931 * @cur: the XML node
932 * @type: the type of Catalog entry
933 * @name: the name of the node
934 * @attrName: the attribute holding the value
935 * @uriAttrName: the attribute holding the URI-Reference
936 * @prefer: the PUBLIC vs. SYSTEM current preference value
937 *
938 * Finishes the examination of an XML tree node of a catalog and build
939 * a Catalog entry from it.
940 *
941 * Returns the new Catalog entry node or NULL in case of error.
942 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000943static xmlCatalogEntryPtr
944xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
945 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000946 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000947 int ok = 1;
948 xmlChar *uriValue;
949 xmlChar *nameValue = NULL;
950 xmlChar *base = NULL;
951 xmlChar *URL = NULL;
952 xmlCatalogEntryPtr ret = NULL;
953
954 if (attrName != NULL) {
955 nameValue = xmlGetProp(cur, attrName);
956 if (nameValue == NULL) {
957 xmlGenericError(xmlGenericErrorContext,
958 "%s entry lacks '%s'\n", name, attrName);
959 ok = 0;
960 }
961 }
962 uriValue = xmlGetProp(cur, uriAttrName);
963 if (uriValue == NULL) {
964 xmlGenericError(xmlGenericErrorContext,
965 "%s entry lacks '%s'\n", name, uriAttrName);
966 ok = 0;
967 }
968 if (!ok) {
969 if (nameValue != NULL)
970 xmlFree(nameValue);
971 if (uriValue != NULL)
972 xmlFree(uriValue);
973 return(NULL);
974 }
975
976 base = xmlNodeGetBase(cur->doc, cur);
977 URL = xmlBuildURI(uriValue, base);
978 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000979 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000980 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000981 xmlGenericError(xmlGenericErrorContext,
982 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000983 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000984 xmlGenericError(xmlGenericErrorContext,
985 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000986 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000987 ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000988 } else {
989 xmlGenericError(xmlGenericErrorContext,
990 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
991 }
992 if (nameValue != NULL)
993 xmlFree(nameValue);
994 if (uriValue != NULL)
995 xmlFree(uriValue);
996 if (base != NULL)
997 xmlFree(base);
998 if (URL != NULL)
999 xmlFree(URL);
1000 return(ret);
1001}
1002
Daniel Veillard75b96822001-10-11 18:59:45 +00001003/**
1004 * xmlParseXMLCatalogNode:
1005 * @cur: the XML node
1006 * @prefer: the PUBLIC vs. SYSTEM current preference value
1007 * @parent: the parent Catalog entry
1008 *
1009 * Examines an XML tree node of a catalog and build
1010 * a Catalog entry from it adding it to its parent. The examination can
1011 * be recursive.
1012 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001013static void
1014xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1015 xmlCatalogEntryPtr parent)
1016{
1017 xmlChar *uri = NULL;
1018 xmlChar *URL = NULL;
1019 xmlChar *base = NULL;
1020 xmlCatalogEntryPtr entry = NULL;
1021
1022 if (cur == NULL)
1023 return;
1024 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1025 xmlChar *prop;
1026
1027 prop = xmlGetProp(cur, BAD_CAST "prefer");
1028 if (prop != NULL) {
1029 if (xmlStrEqual(prop, BAD_CAST "system")) {
1030 prefer = XML_CATA_PREFER_SYSTEM;
1031 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1032 prefer = XML_CATA_PREFER_PUBLIC;
1033 } else {
1034 xmlGenericError(xmlGenericErrorContext,
1035 "Invalid value for prefer: '%s'\n", prop);
1036 }
1037 xmlFree(prop);
1038 }
1039 /*
1040 * Recurse to propagate prefer to the subtree
1041 * (xml:base handling is automated)
1042 */
1043 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
1044 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1045 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001046 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001047 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1048 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001049 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001050 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1051 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1052 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001053 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001054 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1055 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1056 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001057 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001058 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1059 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1060 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001061 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001062 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1063 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1064 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001065 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001066 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1067 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1068 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001069 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001070 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1071 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1072 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001073 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001074 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1075 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1076 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001077 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001078 }
1079 if ((entry != NULL) && (parent != NULL)) {
1080 entry->parent = parent;
1081 if (parent->children == NULL)
1082 parent->children = entry;
1083 else {
1084 xmlCatalogEntryPtr prev;
1085
1086 prev = parent->children;
1087 while (prev->next != NULL)
1088 prev = prev->next;
1089 prev->next = entry;
1090 }
1091 }
1092 if (base != NULL)
1093 xmlFree(base);
1094 if (uri != NULL)
1095 xmlFree(uri);
1096 if (URL != NULL)
1097 xmlFree(URL);
1098}
1099
Daniel Veillard75b96822001-10-11 18:59:45 +00001100/**
1101 * xmlParseXMLCatalogNodeList:
1102 * @cur: the XML node list of siblings
1103 * @prefer: the PUBLIC vs. SYSTEM current preference value
1104 * @parent: the parent Catalog entry
1105 *
1106 * Examines a list of XML sibling nodes of a catalog and build
1107 * a list of Catalog entry from it adding it to the parent.
1108 * The examination will recurse to examine node subtrees.
1109 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001110static void
1111xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1112 xmlCatalogEntryPtr parent) {
1113 while (cur != NULL) {
1114 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1115 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1116 xmlParseXMLCatalogNode(cur, prefer, parent);
1117 }
1118 cur = cur->next;
1119 }
1120 /* TODO: sort the list according to REWRITE lengths and prefer value */
1121}
1122
Daniel Veillard75b96822001-10-11 18:59:45 +00001123/**
1124 * xmlParseXMLCatalog:
1125 * @value: the content in-memory of the catalog serialization
1126 * @prefer: the PUBLIC vs. SYSTEM current preference value
1127 * @file: the filename for the catalog
1128 *
1129 * Parses the catalog content to extract the XML tree and then analyze the
1130 * tree to build a list of Catalog entries corresponding to this catalog
1131 *
1132 * Returns the resulting Catalog entries list
1133 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001134static xmlCatalogEntryPtr
1135xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
1136 const char *file) {
1137 xmlDocPtr doc;
1138 xmlNodePtr cur;
1139 xmlChar *prop;
1140 xmlCatalogEntryPtr parent = NULL;
1141
1142 if ((value == NULL) || (file == NULL))
1143 return(NULL);
1144
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001145 if (xmlDebugCatalogs)
1146 xmlGenericError(xmlGenericErrorContext,
1147 "Parsing catalog %s's content\n", file);
1148
Daniel Veillard344cee72001-08-20 00:08:40 +00001149 doc = xmlParseDoc((xmlChar *) value);
1150 if (doc == NULL)
1151 return(NULL);
1152 doc->URL = xmlStrdup((const xmlChar *) file);
1153
1154 cur = xmlDocGetRootElement(doc);
1155 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1156 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1157 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1158
Daniel Veillard344cee72001-08-20 00:08:40 +00001159 prop = xmlGetProp(cur, BAD_CAST "prefer");
1160 if (prop != NULL) {
1161 if (xmlStrEqual(prop, BAD_CAST "system")) {
1162 prefer = XML_CATA_PREFER_SYSTEM;
1163 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1164 prefer = XML_CATA_PREFER_PUBLIC;
1165 } else {
1166 xmlGenericError(xmlGenericErrorContext,
1167 "Invalid value for prefer: '%s'\n",
1168 prop);
1169 }
1170 xmlFree(prop);
1171 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001172 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1173 (const xmlChar *)file, prefer);
1174 if (parent == NULL) {
1175 xmlFreeDoc(doc);
1176 return(NULL);
1177 }
1178
Daniel Veillard344cee72001-08-20 00:08:40 +00001179 cur = cur->children;
1180 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1181 } else {
1182 xmlGenericError(xmlGenericErrorContext,
1183 "File %s is not an XML Catalog\n", file);
1184 xmlFreeDoc(doc);
1185 return(NULL);
1186 }
1187 xmlFreeDoc(doc);
1188 return(parent);
1189}
1190
Daniel Veillard75b96822001-10-11 18:59:45 +00001191/**
1192 * xmlParseXMLCatalogFile:
1193 * @prefer: the PUBLIC vs. SYSTEM current preference value
1194 * @filename: the filename for the catalog
1195 *
1196 * Parses the catalog file to extract the XML tree and then analyze the
1197 * tree to build a list of Catalog entries corresponding to this catalog
1198 *
1199 * Returns the resulting Catalog entries list
1200 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001201static xmlCatalogEntryPtr
1202xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1203 xmlDocPtr doc;
1204 xmlNodePtr cur;
1205 xmlChar *prop;
1206 xmlCatalogEntryPtr parent = NULL;
1207
1208 if (filename == NULL)
1209 return(NULL);
1210
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001211 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001212 if (doc == NULL) {
1213 if (xmlDebugCatalogs)
1214 xmlGenericError(xmlGenericErrorContext,
1215 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001216 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001217 }
1218
1219 if (xmlDebugCatalogs)
1220 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001221 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001222
1223 cur = xmlDocGetRootElement(doc);
1224 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1225 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1226 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1227
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001228 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1229 (const xmlChar *)filename, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001230 if (parent == NULL) {
1231 xmlFreeDoc(doc);
1232 return(NULL);
1233 }
1234
1235 prop = xmlGetProp(cur, BAD_CAST "prefer");
1236 if (prop != NULL) {
1237 if (xmlStrEqual(prop, BAD_CAST "system")) {
1238 prefer = XML_CATA_PREFER_SYSTEM;
1239 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1240 prefer = XML_CATA_PREFER_PUBLIC;
1241 } else {
1242 xmlGenericError(xmlGenericErrorContext,
1243 "Invalid value for prefer: '%s'\n",
1244 prop);
1245 }
1246 xmlFree(prop);
1247 }
1248 cur = cur->children;
1249 xmlParseXMLCatalogNodeList(cur, prefer, parent);
1250 } else {
1251 xmlGenericError(xmlGenericErrorContext,
1252 "File %s is not an XML Catalog\n", filename);
1253 xmlFreeDoc(doc);
1254 return(NULL);
1255 }
1256 xmlFreeDoc(doc);
1257 return(parent);
1258}
1259
Daniel Veillardcda96922001-08-21 10:56:31 +00001260/**
1261 * xmlFetchXMLCatalogFile:
1262 * @catal: an existing but incomplete catalog entry
1263 *
1264 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardcda96922001-08-21 10:56:31 +00001265 *
1266 * Returns 0 in case of success, -1 otherwise
1267 */
1268static int
1269xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001270 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001271
1272 if (catal == NULL)
1273 return(-1);
1274 if (catal->value == NULL)
1275 return(-1);
1276 if (catal->children != NULL)
1277 return(-1);
1278
Daniel Veillard81463942001-10-16 12:34:39 +00001279 /*
1280 * lock the whole catalog for modification
1281 */
1282 xmlRMutexLock(xmlCatalogMutex);
1283 if (catal->children != NULL) {
1284 /* Okay someone else did it in the meantime */
1285 xmlRMutexUnlock(xmlCatalogMutex);
1286 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001287 }
1288
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001289 if (xmlCatalogXMLFiles != NULL) {
1290 doc = (xmlCatalogEntryPtr)
Daniel Veillard6990bf32001-08-23 21:17:48 +00001291 xmlHashLookup(xmlCatalogXMLFiles, catal->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001292 if (doc != NULL) {
1293 if (xmlDebugCatalogs)
1294 xmlGenericError(xmlGenericErrorContext,
1295 "Found %s in file hash\n", catal->value);
1296
1297 if (catal->type == XML_CATA_CATALOG)
1298 catal->children = doc->children;
1299 else
1300 catal->children = doc;
1301 catal->dealloc = 0;
1302 xmlRMutexUnlock(xmlCatalogMutex);
1303 return(0);
1304 }
1305 if (xmlDebugCatalogs)
1306 xmlGenericError(xmlGenericErrorContext,
1307 "%s not found in file hash\n", catal->value);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001308 }
1309
Daniel Veillardcda96922001-08-21 10:56:31 +00001310 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001311 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1312 * use the existing catalog, there is no recusivity allowed at
1313 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001314 */
Daniel Veillard6990bf32001-08-23 21:17:48 +00001315 doc = xmlParseXMLCatalogFile(catal->prefer, catal->value);
1316 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001317 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001318 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001319 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001320 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001321
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001322 if (catal->type == XML_CATA_CATALOG)
1323 catal->children = doc->children;
1324 else
1325 catal->children = doc;
1326
1327 doc->dealloc = 1;
1328
Daniel Veillard81463942001-10-16 12:34:39 +00001329 if (xmlCatalogXMLFiles == NULL)
1330 xmlCatalogXMLFiles = xmlHashCreate(10);
1331 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001332 if (xmlDebugCatalogs)
1333 xmlGenericError(xmlGenericErrorContext,
1334 "%s added to file hash\n", catal->value);
1335 xmlHashAddEntry(xmlCatalogXMLFiles, catal->value, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001336 }
Daniel Veillard81463942001-10-16 12:34:39 +00001337 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001338 return(0);
1339}
1340
Daniel Veillard75b96822001-10-11 18:59:45 +00001341/************************************************************************
1342 * *
1343 * XML Catalog handling *
1344 * *
1345 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001346
1347/**
1348 * xmlAddXMLCatalog:
1349 * @catal: top of an XML catalog
1350 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001351 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001352 * @replace: the replacement value for the match
1353 *
1354 * Add an entry in the XML catalog, it may overwrite existing but
1355 * different entries.
1356 *
1357 * Returns 0 if successful, -1 otherwise
1358 */
1359static int
1360xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1361 const xmlChar *orig, const xmlChar *replace) {
1362 xmlCatalogEntryPtr cur;
1363 xmlCatalogEntryType typ;
1364
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001365 if ((catal == NULL) ||
1366 ((catal->type != XML_CATA_CATALOG) &&
1367 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001368 return(-1);
1369 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001370 if (typ == XML_CATA_NONE) {
1371 if (xmlDebugCatalogs)
1372 xmlGenericError(xmlGenericErrorContext,
1373 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001374 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001375 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001376
1377 cur = catal->children;
1378 /*
1379 * Might be a simple "update in place"
1380 */
1381 if (cur != NULL) {
1382 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001383 if ((orig != NULL) && (cur->type == typ) &&
1384 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001385 if (xmlDebugCatalogs)
1386 xmlGenericError(xmlGenericErrorContext,
1387 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001388 if (cur->value != NULL)
1389 xmlFree(cur->value);
1390 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001391 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001392 }
1393 if (cur->next == NULL)
1394 break;
1395 cur = cur->next;
1396 }
1397 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001398 if (xmlDebugCatalogs)
1399 xmlGenericError(xmlGenericErrorContext,
1400 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001401 if (cur == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001402 catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001403 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001404 cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillardcda96922001-08-21 10:56:31 +00001405 return(0);
1406}
1407
1408/**
1409 * xmlDelXMLCatalog:
1410 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001411 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001412 *
1413 * Remove entries in the XML catalog where the value or the URI
1414 * is equal to @value
1415 *
1416 * Returns the number of entries removed if successful, -1 otherwise
1417 */
1418static int
1419xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1420 xmlCatalogEntryPtr cur, prev, tmp;
1421 int ret = 0;
1422
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001423 if ((catal == NULL) ||
1424 ((catal->type != XML_CATA_CATALOG) &&
1425 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001426 return(-1);
1427 if (value == NULL)
1428 return(-1);
1429
1430 /*
1431 * Scan the children
1432 */
1433 cur = catal->children;
1434 prev = NULL;
1435 while (cur != NULL) {
1436 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1437 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001438 if (xmlDebugCatalogs) {
1439 if (cur->name != NULL)
1440 xmlGenericError(xmlGenericErrorContext,
1441 "Removing element %s from catalog\n", cur->name);
1442 else
1443 xmlGenericError(xmlGenericErrorContext,
1444 "Removing element %s from catalog\n", cur->value);
1445 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001446 ret++;
1447 tmp = cur;
1448 cur = tmp->next;
1449 if (prev == NULL) {
1450 catal->children = cur;
1451 } else {
1452 prev->next = cur;
1453 }
1454 xmlFreeCatalogEntry(tmp);
1455 continue;
1456 }
1457 prev = cur;
1458 cur = cur->next;
1459 }
1460 return(ret);
1461}
1462
1463/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001464 * xmlCatalogXMLResolve:
1465 * @catal: a catalog list
1466 * @pubId: the public ID string
1467 * @sysId: the system ID string
1468 *
1469 * Do a complete resolution lookup of an External Identifier for a
1470 * list of catalog entries.
1471 *
1472 * Implements (or tries to) 7.1. External Identifier Resolution
1473 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1474 *
1475 * Returns the URI of the resource or NULL if not found
1476 */
1477static xmlChar *
1478xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1479 const xmlChar *sysID) {
1480 xmlChar *ret = NULL;
1481 xmlCatalogEntryPtr cur;
1482 int haveDelegate = 0;
1483 int haveNext = 0;
1484
1485 /*
1486 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1487 */
1488 if (sysID != NULL) {
1489 xmlCatalogEntryPtr rewrite = NULL;
1490 int lenrewrite = 0, len;
1491 cur = catal;
1492 haveDelegate = 0;
1493 while (cur != NULL) {
1494 switch (cur->type) {
1495 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001496 if (xmlStrEqual(sysID, cur->name)) {
1497 if (xmlDebugCatalogs)
1498 xmlGenericError(xmlGenericErrorContext,
1499 "Found system match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001500 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001501 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001502 break;
1503 case XML_CATA_REWRITE_SYSTEM:
1504 len = xmlStrlen(cur->name);
1505 if ((len > lenrewrite) &&
1506 (!xmlStrncmp(sysID, cur->name, len))) {
1507 lenrewrite = len;
1508 rewrite = cur;
1509 }
1510 break;
1511 case XML_CATA_DELEGATE_SYSTEM:
1512 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1513 haveDelegate++;
1514 break;
1515 case XML_CATA_NEXT_CATALOG:
1516 haveNext++;
1517 break;
1518 default:
1519 break;
1520 }
1521 cur = cur->next;
1522 }
1523 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001524 if (xmlDebugCatalogs)
1525 xmlGenericError(xmlGenericErrorContext,
1526 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001527 ret = xmlStrdup(rewrite->value);
1528 if (ret != NULL)
1529 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1530 return(ret);
1531 }
1532 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001533 const xmlChar *delegates[MAX_DELEGATE];
1534 int nbList = 0, i;
1535
Daniel Veillardcda96922001-08-21 10:56:31 +00001536 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001537 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001538 * matches when the list was produced.
1539 */
1540 cur = catal;
1541 while (cur != NULL) {
1542 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1543 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001544 for (i = 0;i < nbList;i++)
1545 if (xmlStrEqual(cur->value, delegates[i]))
1546 break;
1547 if (i < nbList) {
1548 cur = cur->next;
1549 continue;
1550 }
1551 if (nbList < MAX_DELEGATE)
1552 delegates[nbList++] = cur->value;
1553
Daniel Veillardcda96922001-08-21 10:56:31 +00001554 if (cur->children == NULL) {
1555 xmlFetchXMLCatalogFile(cur);
1556 }
1557 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001558 if (xmlDebugCatalogs)
1559 xmlGenericError(xmlGenericErrorContext,
1560 "Trying system delegate %s\n", cur->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001561 ret = xmlCatalogListXMLResolve(
1562 cur->children, NULL, sysID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001563 if (ret != NULL)
1564 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001565 }
1566 }
1567 cur = cur->next;
1568 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001569 /*
1570 * Apply the cut algorithm explained in 4/
1571 */
1572 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001573 }
1574 }
1575 /*
1576 * Then tries 5/ 6/ if a public ID is provided
1577 */
1578 if (pubID != NULL) {
1579 cur = catal;
1580 haveDelegate = 0;
1581 while (cur != NULL) {
1582 switch (cur->type) {
1583 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001584 if (xmlStrEqual(pubID, cur->name)) {
1585 if (xmlDebugCatalogs)
1586 xmlGenericError(xmlGenericErrorContext,
1587 "Found public match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001588 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001589 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001590 break;
1591 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001592 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1593 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001594 haveDelegate++;
1595 break;
1596 case XML_CATA_NEXT_CATALOG:
1597 if (sysID == NULL)
1598 haveNext++;
1599 break;
1600 default:
1601 break;
1602 }
1603 cur = cur->next;
1604 }
1605 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001606 const xmlChar *delegates[MAX_DELEGATE];
1607 int nbList = 0, i;
1608
Daniel Veillardcda96922001-08-21 10:56:31 +00001609 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001610 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001611 * matches when the list was produced.
1612 */
1613 cur = catal;
1614 while (cur != NULL) {
1615 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001616 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1617 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001618
1619 for (i = 0;i < nbList;i++)
1620 if (xmlStrEqual(cur->value, delegates[i]))
1621 break;
1622 if (i < nbList) {
1623 cur = cur->next;
1624 continue;
1625 }
1626 if (nbList < MAX_DELEGATE)
1627 delegates[nbList++] = cur->value;
1628
Daniel Veillardcda96922001-08-21 10:56:31 +00001629 if (cur->children == NULL) {
1630 xmlFetchXMLCatalogFile(cur);
1631 }
1632 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001633 if (xmlDebugCatalogs)
1634 xmlGenericError(xmlGenericErrorContext,
1635 "Trying public delegate %s\n", cur->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001636 ret = xmlCatalogListXMLResolve(
1637 cur->children, pubID, NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001638 if (ret != NULL)
1639 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001640 }
1641 }
1642 cur = cur->next;
1643 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001644 /*
1645 * Apply the cut algorithm explained in 4/
1646 */
1647 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001648 }
1649 }
1650 if (haveNext) {
1651 cur = catal;
1652 while (cur != NULL) {
1653 if (cur->type == XML_CATA_NEXT_CATALOG) {
1654 if (cur->children == NULL) {
1655 xmlFetchXMLCatalogFile(cur);
1656 }
1657 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001658 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1659 if (ret != NULL)
1660 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001661 }
1662 }
1663 cur = cur->next;
1664 }
1665 }
1666
1667 return(NULL);
1668}
1669
1670/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001671 * xmlCatalogXMLResolveURI:
1672 * @catal: a catalog list
1673 * @URI: the URI
1674 * @sysId: the system ID string
1675 *
1676 * Do a complete resolution lookup of an External Identifier for a
1677 * list of catalog entries.
1678 *
1679 * Implements (or tries to) 7.2.2. URI Resolution
1680 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1681 *
1682 * Returns the URI of the resource or NULL if not found
1683 */
1684static xmlChar *
1685xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1686 xmlChar *ret = NULL;
1687 xmlCatalogEntryPtr cur;
1688 int haveDelegate = 0;
1689 int haveNext = 0;
1690 xmlCatalogEntryPtr rewrite = NULL;
1691 int lenrewrite = 0, len;
1692
1693 if (catal == NULL)
1694 return(NULL);
1695
1696 if (URI == NULL)
1697 return(NULL);
1698
1699 /*
1700 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1701 */
1702 cur = catal;
1703 haveDelegate = 0;
1704 while (cur != NULL) {
1705 switch (cur->type) {
1706 case XML_CATA_URI:
1707 if (xmlStrEqual(URI, cur->name)) {
1708 if (xmlDebugCatalogs)
1709 xmlGenericError(xmlGenericErrorContext,
1710 "Found URI match %s\n", cur->name);
1711 return(xmlStrdup(cur->value));
1712 }
1713 break;
1714 case XML_CATA_REWRITE_URI:
1715 len = xmlStrlen(cur->name);
1716 if ((len > lenrewrite) &&
1717 (!xmlStrncmp(URI, cur->name, len))) {
1718 lenrewrite = len;
1719 rewrite = cur;
1720 }
1721 break;
1722 case XML_CATA_DELEGATE_URI:
1723 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1724 haveDelegate++;
1725 break;
1726 case XML_CATA_NEXT_CATALOG:
1727 haveNext++;
1728 break;
1729 default:
1730 break;
1731 }
1732 cur = cur->next;
1733 }
1734 if (rewrite != NULL) {
1735 if (xmlDebugCatalogs)
1736 xmlGenericError(xmlGenericErrorContext,
1737 "Using rewriting rule %s\n", rewrite->name);
1738 ret = xmlStrdup(rewrite->value);
1739 if (ret != NULL)
1740 ret = xmlStrcat(ret, &URI[lenrewrite]);
1741 return(ret);
1742 }
1743 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001744 const xmlChar *delegates[MAX_DELEGATE];
1745 int nbList = 0, i;
1746
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001747 /*
1748 * Assume the entries have been sorted by decreasing substring
1749 * matches when the list was produced.
1750 */
1751 cur = catal;
1752 while (cur != NULL) {
1753 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1754 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001755 for (i = 0;i < nbList;i++)
1756 if (xmlStrEqual(cur->value, delegates[i]))
1757 break;
1758 if (i < nbList) {
1759 cur = cur->next;
1760 continue;
1761 }
1762 if (nbList < MAX_DELEGATE)
1763 delegates[nbList++] = cur->value;
1764
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001765 if (cur->children == NULL) {
1766 xmlFetchXMLCatalogFile(cur);
1767 }
1768 if (cur->children != NULL) {
1769 if (xmlDebugCatalogs)
1770 xmlGenericError(xmlGenericErrorContext,
1771 "Trying URI delegate %s\n", cur->value);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001772 ret = xmlCatalogListXMLResolveURI(
1773 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001774 if (ret != NULL)
1775 return(ret);
1776 }
1777 }
1778 cur = cur->next;
1779 }
1780 /*
1781 * Apply the cut algorithm explained in 4/
1782 */
1783 return(XML_CATAL_BREAK);
1784 }
1785 if (haveNext) {
1786 cur = catal;
1787 while (cur != NULL) {
1788 if (cur->type == XML_CATA_NEXT_CATALOG) {
1789 if (cur->children == NULL) {
1790 xmlFetchXMLCatalogFile(cur);
1791 }
1792 if (cur->children != NULL) {
1793 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1794 if (ret != NULL)
1795 return(ret);
1796 }
1797 }
1798 cur = cur->next;
1799 }
1800 }
1801
1802 return(NULL);
1803}
1804
1805/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001806 * xmlCatalogListXMLResolve:
1807 * @catal: a catalog list
1808 * @pubId: the public ID string
1809 * @sysId: the system ID string
1810 *
1811 * Do a complete resolution lookup of an External Identifier for a
1812 * list of catalogs
1813 *
1814 * Implements (or tries to) 7.1. External Identifier Resolution
1815 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1816 *
1817 * Returns the URI of the resource or NULL if not found
1818 */
1819static xmlChar *
1820xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1821 const xmlChar *sysID) {
1822 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001823 xmlChar *urnID = NULL;
1824
1825 if (catal == NULL)
1826 return(NULL);
1827 if ((pubID == NULL) && (sysID == NULL))
1828 return(NULL);
1829
1830 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1831 urnID = xmlCatalogUnWrapURN(pubID);
1832 if (xmlDebugCatalogs) {
1833 if (urnID == NULL)
1834 xmlGenericError(xmlGenericErrorContext,
1835 "Public URN ID %s expanded to NULL\n", pubID);
1836 else
1837 xmlGenericError(xmlGenericErrorContext,
1838 "Public URN ID expanded to %s\n", urnID);
1839 }
1840 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1841 if (urnID != NULL)
1842 xmlFree(urnID);
1843 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001844 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001845 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1846 urnID = xmlCatalogUnWrapURN(sysID);
1847 if (xmlDebugCatalogs) {
1848 if (urnID == NULL)
1849 xmlGenericError(xmlGenericErrorContext,
1850 "System URN ID %s expanded to NULL\n", sysID);
1851 else
1852 xmlGenericError(xmlGenericErrorContext,
1853 "System URN ID expanded to %s\n", urnID);
1854 }
1855 if (pubID == NULL)
1856 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1857 else if (xmlStrEqual(pubID, urnID))
1858 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1859 else {
1860 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1861 }
1862 if (urnID != NULL)
1863 xmlFree(urnID);
1864 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001865 }
1866 while (catal != NULL) {
1867 if (catal->type == XML_CATA_CATALOG) {
1868 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001869 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001870 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001871 if (catal->children != NULL) {
1872 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1873 if (ret != NULL)
1874 return(ret);
1875 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001876 }
1877 catal = catal->next;
1878 }
1879 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001880}
1881
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001882/**
1883 * xmlCatalogListXMLResolveURI:
1884 * @catal: a catalog list
1885 * @URI: the URI
1886 *
1887 * Do a complete resolution lookup of an URI for a list of catalogs
1888 *
1889 * Implements (or tries to) 7.2. URI Resolution
1890 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1891 *
1892 * Returns the URI of the resource or NULL if not found
1893 */
1894static xmlChar *
1895xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1896 xmlChar *ret = NULL;
1897 xmlChar *urnID = NULL;
1898
1899 if (catal == NULL)
1900 return(NULL);
1901 if (URI == NULL)
1902 return(NULL);
1903
1904 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1905 urnID = xmlCatalogUnWrapURN(URI);
1906 if (xmlDebugCatalogs) {
1907 if (urnID == NULL)
1908 xmlGenericError(xmlGenericErrorContext,
1909 "URN ID %s expanded to NULL\n", URI);
1910 else
1911 xmlGenericError(xmlGenericErrorContext,
1912 "URN ID expanded to %s\n", urnID);
1913 }
1914 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1915 if (urnID != NULL)
1916 xmlFree(urnID);
1917 return(ret);
1918 }
1919 while (catal != NULL) {
1920 if (catal->type == XML_CATA_CATALOG) {
1921 if (catal->children == NULL) {
1922 xmlFetchXMLCatalogFile(catal);
1923 }
1924 if (catal->children != NULL) {
1925 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1926 if (ret != NULL)
1927 return(ret);
1928 }
1929 }
1930 catal = catal->next;
1931 }
1932 return(ret);
1933}
1934
Daniel Veillard344cee72001-08-20 00:08:40 +00001935/************************************************************************
1936 * *
1937 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001938 * *
1939 ************************************************************************/
1940
1941
1942#define RAW *cur
1943#define NEXT cur++;
1944#define SKIP(x) cur += x;
1945
1946#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1947
Daniel Veillard75b96822001-10-11 18:59:45 +00001948/**
1949 * xmlParseSGMLCatalogComment:
1950 * @cur: the current character
1951 *
1952 * Skip a comment in an SGML catalog
1953 *
1954 * Returns new current character
1955 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001956static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001957xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001958 if ((cur[0] != '-') || (cur[1] != '-'))
1959 return(cur);
1960 SKIP(2);
1961 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1962 NEXT;
1963 if (cur[0] == 0) {
1964 return(NULL);
1965 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001966 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001967}
1968
Daniel Veillard75b96822001-10-11 18:59:45 +00001969/**
1970 * xmlParseSGMLCatalogPubid:
1971 * @cur: the current character
1972 * @id: the return location
1973 *
1974 * Parse an SGML catalog ID
1975 *
1976 * Returns new current character and store the value in @id
1977 */
Daniel Veillarda7374592001-05-10 14:17:55 +00001978static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001979xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001980 xmlChar *buf = NULL;
1981 int len = 0;
1982 int size = 50;
1983 xmlChar stop;
1984 int count = 0;
1985
1986 *id = NULL;
1987
1988 if (RAW == '"') {
1989 NEXT;
1990 stop = '"';
1991 } else if (RAW == '\'') {
1992 NEXT;
1993 stop = '\'';
1994 } else {
1995 stop = ' ';
1996 }
1997 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1998 if (buf == NULL) {
1999 xmlGenericError(xmlGenericErrorContext,
2000 "malloc of %d byte failed\n", size);
2001 return(NULL);
2002 }
2003 while (xmlIsPubidChar(*cur)) {
2004 if ((*cur == stop) && (stop != ' '))
2005 break;
2006 if ((stop == ' ') && (IS_BLANK(*cur)))
2007 break;
2008 if (len + 1 >= size) {
2009 size *= 2;
2010 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2011 if (buf == NULL) {
2012 xmlGenericError(xmlGenericErrorContext,
2013 "realloc of %d byte failed\n", size);
2014 return(NULL);
2015 }
2016 }
2017 buf[len++] = *cur;
2018 count++;
2019 NEXT;
2020 }
2021 buf[len] = 0;
2022 if (stop == ' ') {
2023 if (!IS_BLANK(*cur)) {
2024 xmlFree(buf);
2025 return(NULL);
2026 }
2027 } else {
2028 if (*cur != stop) {
2029 xmlFree(buf);
2030 return(NULL);
2031 }
2032 NEXT;
2033 }
2034 *id = buf;
2035 return(cur);
2036}
2037
Daniel Veillard75b96822001-10-11 18:59:45 +00002038/**
2039 * xmlParseSGMLCatalogName:
2040 * @cur: the current character
2041 * @name: the return location
2042 *
2043 * Parse an SGML catalog name
2044 *
2045 * Returns new current character and store the value in @name
2046 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002047static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002048xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002049 xmlChar buf[XML_MAX_NAMELEN + 5];
2050 int len = 0;
2051 int c;
2052
2053 *name = NULL;
2054
2055 /*
2056 * Handler for more complex cases
2057 */
2058 c = *cur;
2059 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2060 return(NULL);
2061 }
2062
2063 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2064 (c == '.') || (c == '-') ||
2065 (c == '_') || (c == ':'))) {
2066 buf[len++] = c;
2067 cur++;
2068 c = *cur;
2069 if (len >= XML_MAX_NAMELEN)
2070 return(NULL);
2071 }
2072 *name = xmlStrndup(buf, len);
2073 return(cur);
2074}
2075
Daniel Veillard75b96822001-10-11 18:59:45 +00002076/**
2077 * xmlGetSGMLCatalogEntryType:
2078 * @name: the entry name
2079 *
2080 * Get the Catalog entry type for a given SGML Catalog name
2081 *
2082 * Returns Catalog entry type
2083 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002084static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002085xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002086 xmlCatalogEntryType type = XML_CATA_NONE;
2087 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2088 type = SGML_CATA_SYSTEM;
2089 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2090 type = SGML_CATA_PUBLIC;
2091 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2092 type = SGML_CATA_DELEGATE;
2093 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2094 type = SGML_CATA_ENTITY;
2095 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2096 type = SGML_CATA_DOCTYPE;
2097 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2098 type = SGML_CATA_LINKTYPE;
2099 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2100 type = SGML_CATA_NOTATION;
2101 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2102 type = SGML_CATA_SGMLDECL;
2103 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2104 type = SGML_CATA_DOCUMENT;
2105 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2106 type = SGML_CATA_CATALOG;
2107 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2108 type = SGML_CATA_BASE;
2109 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2110 type = SGML_CATA_DELEGATE;
2111 return(type);
2112}
2113
Daniel Veillard75b96822001-10-11 18:59:45 +00002114/**
2115 * xmlParseSGMLCatalog:
2116 * @catal: the SGML Catalog
2117 * @value: the content of the SGML Catalog serialization
2118 * @file: the filepath for the catalog
2119 * @super: should this be handled as a Super Catalog in which case
2120 * parsing is not recursive
2121 *
2122 * Parse an SGML catalog content and fill up the @catal hash table with
2123 * the new entries found.
2124 *
2125 * Returns 0 in case of success, -1 in case of error.
2126 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002127static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002128xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2129 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002130 const xmlChar *cur = value;
2131 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002132 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002133
2134 if ((cur == NULL) || (file == NULL))
2135 return(-1);
2136 base = xmlStrdup((const xmlChar *) file);
2137
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002138 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002139 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002140 if (cur[0] == 0)
2141 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002142 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002143 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002144 if (cur == NULL) {
2145 /* error */
2146 break;
2147 }
2148 } else {
2149 xmlChar *sysid = NULL;
2150 xmlChar *name = NULL;
2151 xmlCatalogEntryType type = XML_CATA_NONE;
2152
Daniel Veillardcda96922001-08-21 10:56:31 +00002153 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002154 if (name == NULL) {
2155 /* error */
2156 break;
2157 }
2158 if (!IS_BLANK(*cur)) {
2159 /* error */
2160 break;
2161 }
2162 SKIP_BLANKS;
2163 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002164 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002165 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002166 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002167 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002168 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002169 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002170 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002171 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002172 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002173 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002174 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002175 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002176 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002177 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002178 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002179 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002180 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002181 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002182 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002183 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002184 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002185 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002186 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002187 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2188 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002189 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002190 if (name == NULL) {
2191 /* error */
2192 break;
2193 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002194 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002195 continue;
2196 }
2197 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002198 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002199
2200 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002201 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002202 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002203 type = SGML_CATA_PENTITY;
2204 case SGML_CATA_PENTITY:
2205 case SGML_CATA_DOCTYPE:
2206 case SGML_CATA_LINKTYPE:
2207 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002208 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002209 if (cur == NULL) {
2210 /* error */
2211 break;
2212 }
2213 if (!IS_BLANK(*cur)) {
2214 /* error */
2215 break;
2216 }
2217 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002218 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002219 if (cur == NULL) {
2220 /* error */
2221 break;
2222 }
2223 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002224 case SGML_CATA_PUBLIC:
2225 case SGML_CATA_SYSTEM:
2226 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002227 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002228 if (cur == NULL) {
2229 /* error */
2230 break;
2231 }
2232 if (!IS_BLANK(*cur)) {
2233 /* error */
2234 break;
2235 }
2236 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002237 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002238 if (cur == NULL) {
2239 /* error */
2240 break;
2241 }
2242 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002243 case SGML_CATA_BASE:
2244 case SGML_CATA_CATALOG:
2245 case SGML_CATA_DOCUMENT:
2246 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002247 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002248 if (cur == NULL) {
2249 /* error */
2250 break;
2251 }
2252 break;
2253 default:
2254 break;
2255 }
2256 if (cur == NULL) {
2257 if (name != NULL)
2258 xmlFree(name);
2259 if (sysid != NULL)
2260 xmlFree(sysid);
2261 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002262 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002263 if (base != NULL)
2264 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002265 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002266 } else if ((type == SGML_CATA_PUBLIC) ||
2267 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002268 xmlChar *filename;
2269
2270 filename = xmlBuildURI(sysid, base);
2271 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002272 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002273
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002274 entry = xmlNewCatalogEntry(type, name, filename,
2275 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002276 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002277 if (res < 0) {
2278 xmlFreeCatalogEntry(entry);
2279 }
2280 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002281 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002282
Daniel Veillard344cee72001-08-20 00:08:40 +00002283 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002284 if (super) {
2285 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002286
Daniel Veillard82d75332001-10-08 15:01:59 +00002287 entry = xmlNewCatalogEntry(type, sysid, NULL,
2288 XML_CATA_PREFER_NONE);
Daniel Veillard75b96822001-10-11 18:59:45 +00002289 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002290 if (res < 0) {
2291 xmlFreeCatalogEntry(entry);
2292 }
2293 } else {
2294 xmlChar *filename;
2295
2296 filename = xmlBuildURI(sysid, base);
2297 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002298 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002299 xmlFree(filename);
2300 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002301 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002302 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002303 /*
2304 * drop anything else we won't handle it
2305 */
2306 if (name != NULL)
2307 xmlFree(name);
2308 if (sysid != NULL)
2309 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002310 }
2311 }
2312 if (base != NULL)
2313 xmlFree(base);
2314 if (cur == NULL)
2315 return(-1);
2316 return(0);
2317}
2318
Daniel Veillard75b96822001-10-11 18:59:45 +00002319/************************************************************************
2320 * *
2321 * SGML Catalog handling *
2322 * *
2323 ************************************************************************/
2324
Daniel Veillardcda96922001-08-21 10:56:31 +00002325/**
2326 * xmlCatalogGetSGMLPublic:
2327 * @catal: an SGML catalog hash
2328 * @pubId: the public ID string
2329 *
2330 * Try to lookup the system ID associated to a public ID
2331 *
2332 * Returns the system ID if found or NULL otherwise.
2333 */
2334static const xmlChar *
2335xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2336 xmlCatalogEntryPtr entry;
2337
2338 if (catal == NULL)
2339 return(NULL);
2340
2341 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2342 if (entry == NULL)
2343 return(NULL);
2344 if (entry->type == SGML_CATA_PUBLIC)
2345 return(entry->value);
2346 return(NULL);
2347}
2348
2349/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002350 * xmlCatalogGetSGMLSystem:
2351 * @catal: an SGML catalog hash
2352 * @sysId: the public ID string
2353 *
2354 * Try to lookup the catalog local reference for a system ID
2355 *
2356 * Returns the system ID if found or NULL otherwise.
2357 */
2358static const xmlChar *
2359xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2360 xmlCatalogEntryPtr entry;
2361
2362 if (catal == NULL)
2363 return(NULL);
2364
2365 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2366 if (entry == NULL)
2367 return(NULL);
2368 if (entry->type == SGML_CATA_SYSTEM)
2369 return(entry->value);
2370 return(NULL);
2371}
2372
2373/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002374 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002375 * @catal: the SGML catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00002376 * @pubId: the public ID string
2377 * @sysId: the system ID string
2378 *
2379 * Do a complete resolution lookup of an External Identifier
2380 *
2381 * Returns the URI of the resource or NULL if not found
2382 */
2383static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002384xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2385 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002386 const xmlChar *ret = NULL;
2387
Daniel Veillard75b96822001-10-11 18:59:45 +00002388 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002389 return(NULL);
2390
2391 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002392 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002393 if (ret != NULL)
2394 return(ret);
2395 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002396 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00002397 return(NULL);
2398}
2399
Daniel Veillarda7374592001-05-10 14:17:55 +00002400/************************************************************************
2401 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002402 * Specific Public interfaces *
2403 * *
2404 ************************************************************************/
2405
2406/**
2407 * xmlLoadSGMLSuperCatalog:
2408 * @filename: a file path
2409 *
2410 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2411 * references. This is only needed for manipulating SGML Super Catalogs
2412 * like adding and removing CATALOG or DELEGATE entries.
2413 *
2414 * Returns the catalog parsed or NULL in case of error
2415 */
2416xmlCatalogPtr
2417xmlLoadSGMLSuperCatalog(const char *filename)
2418{
2419 xmlChar *content;
2420 xmlCatalogPtr catal;
2421 int ret;
2422
2423 content = xmlLoadFileContent(filename);
2424 if (content == NULL)
2425 return(NULL);
2426
2427 catal = xmlNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2428 if (catal == NULL) {
2429 xmlFree(content);
2430 return(NULL);
2431 }
2432
2433 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2434 xmlFree(content);
2435 if (ret < 0) {
2436 xmlFreeCatalog(catal);
2437 return(NULL);
2438 }
2439 return (catal);
2440}
2441
2442/**
2443 * xmlLoadACatalog:
2444 * @filename: a file path
2445 *
2446 * Load the catalog and build the associated data structures.
2447 * This can be either an XML Catalog or an SGML Catalog
2448 * It will recurse in SGML CATALOG entries. On the other hand XML
2449 * Catalogs are not handled recursively.
2450 *
2451 * Returns the catalog parsed or NULL in case of error
2452 */
2453xmlCatalogPtr
2454xmlLoadACatalog(const char *filename)
2455{
2456 xmlChar *content;
2457 xmlChar *first;
2458 xmlCatalogPtr catal;
2459 int ret;
2460
2461 content = xmlLoadFileContent(filename);
2462 if (content == NULL)
2463 return(NULL);
2464
2465
2466 first = content;
2467
2468 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2469 (!(((*first >= 'A') && (*first <= 'Z')) ||
2470 ((*first >= 'a') && (*first <= 'z')))))
2471 first++;
2472
2473 if (*first != '<') {
2474 catal = xmlNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2475 if (catal == NULL) {
2476 xmlFree(content);
2477 return(NULL);
2478 }
2479 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2480 if (ret < 0) {
2481 xmlFreeCatalog(catal);
2482 xmlFree(content);
2483 return(NULL);
2484 }
2485 } else {
2486 catal = xmlNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2487 if (catal == NULL) {
2488 xmlFree(content);
2489 return(NULL);
2490 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002491 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG,
2492 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002493 }
2494 xmlFree(content);
2495 return (catal);
2496}
2497
2498/**
2499 * xmlExpandCatalog:
2500 * @catal: a catalog
2501 * @filename: a file path
2502 *
2503 * Load the catalog and expand the existing catal structure.
2504 * This can be either an XML Catalog or an SGML Catalog
2505 *
2506 * Returns 0 in case of success, -1 in case of error
2507 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002508static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002509xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2510{
Daniel Veillard75b96822001-10-11 18:59:45 +00002511 int ret;
2512
2513 if ((catal == NULL) || (filename == NULL))
2514 return(-1);
2515
Daniel Veillard75b96822001-10-11 18:59:45 +00002516
2517 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002518 xmlChar *content;
2519
2520 content = xmlLoadFileContent(filename);
2521 if (content == NULL)
2522 return(-1);
2523
Daniel Veillard75b96822001-10-11 18:59:45 +00002524 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2525 if (ret < 0) {
2526 xmlFree(content);
2527 return(-1);
2528 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002529 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002530 } else {
2531 xmlCatalogEntryPtr tmp, cur;
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002532 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG,
2533 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002534
Daniel Veillard75b96822001-10-11 18:59:45 +00002535 cur = catal->xml;
2536 if (cur == NULL) {
2537 catal->xml = tmp;
2538 } else {
2539 while (cur->next != NULL) cur = cur->next;
2540 cur->next = tmp;
2541 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002542 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002543 return (0);
2544}
2545
2546/**
2547 * xmlACatalogResolveSystem:
2548 * @catal: a Catalog
2549 * @sysId: the public ID string
2550 *
2551 * Try to lookup the catalog resource for a system ID
2552 *
2553 * Returns the system ID if found or NULL otherwise, the value returned
2554 * must be freed by the caller.
2555 */
2556xmlChar *
2557xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2558 xmlChar *ret = NULL;
2559
2560 if ((sysID == NULL) || (catal == NULL))
2561 return(NULL);
2562
2563 if (xmlDebugCatalogs)
2564 xmlGenericError(xmlGenericErrorContext,
2565 "Resolve sysID %s\n", sysID);
2566
2567 if (catal->type == XML_XML_CATALOG_TYPE) {
2568 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2569 if (ret == XML_CATAL_BREAK)
2570 ret = NULL;
2571 } else {
2572 const xmlChar *sgml;
2573
2574 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2575 if (sgml != NULL)
2576 ret = xmlStrdup(sgml);
2577 }
2578 return(ret);
2579}
2580
2581/**
2582 * xmlACatalogResolvePublic:
2583 * @catal: a Catalog
2584 * @pubId: the public ID string
2585 *
2586 * Try to lookup the system ID associated to a public ID in that catalog
2587 *
2588 * Returns the system ID if found or NULL otherwise, the value returned
2589 * must be freed by the caller.
2590 */
2591xmlChar *
2592xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2593 xmlChar *ret = NULL;
2594
2595 if ((pubID == NULL) || (catal == NULL))
2596 return(NULL);
2597
2598 if (xmlDebugCatalogs)
2599 xmlGenericError(xmlGenericErrorContext,
2600 "Resolve pubID %s\n", pubID);
2601
2602 if (catal->type == XML_XML_CATALOG_TYPE) {
2603 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2604 if (ret == XML_CATAL_BREAK)
2605 ret = NULL;
2606 } else {
2607 const xmlChar *sgml;
2608
2609 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2610 if (sgml != NULL)
2611 ret = xmlStrdup(sgml);
2612 }
2613 return(ret);
2614}
2615
2616/**
2617 * xmlACatalogResolve:
2618 * @catal: a Catalog
2619 * @pubId: the public ID string
2620 * @sysId: the system ID string
2621 *
2622 * Do a complete resolution lookup of an External Identifier
2623 *
2624 * Returns the URI of the resource or NULL if not found, it must be freed
2625 * by the caller.
2626 */
2627xmlChar *
2628xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2629 const xmlChar * sysID)
2630{
2631 xmlChar *ret = NULL;
2632
2633 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2634 return (NULL);
2635
2636 if (xmlDebugCatalogs) {
2637 if (pubID != NULL) {
2638 xmlGenericError(xmlGenericErrorContext,
2639 "Resolve: pubID %s\n", pubID);
2640 } else {
2641 xmlGenericError(xmlGenericErrorContext,
2642 "Resolve: sysID %s\n", sysID);
2643 }
2644 }
2645
2646 if (catal->type == XML_XML_CATALOG_TYPE) {
2647 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2648 if (ret == XML_CATAL_BREAK)
2649 ret = NULL;
2650 } else {
2651 const xmlChar *sgml;
2652
2653 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2654 if (sgml != NULL)
2655 ret = xmlStrdup(sgml);
2656 }
2657 return (ret);
2658}
2659
2660/**
2661 * xmlACatalogResolveURI:
2662 * @catal: a Catalog
2663 * @pubId: the URI
2664 *
2665 * Do a complete resolution lookup of an URI
2666 *
2667 * Returns the URI of the resource or NULL if not found, it must be freed
2668 * by the caller.
2669 */
2670xmlChar *
2671xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2672 xmlChar *ret = NULL;
2673
2674 if ((URI == NULL) || (catal == NULL))
2675 return(NULL);
2676
Daniel Veillardb44025c2001-10-11 22:55:55 +00002677 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002678 xmlGenericError(xmlGenericErrorContext,
2679 "Resolve URI %s\n", URI);
2680
2681 if (catal->type == XML_XML_CATALOG_TYPE) {
2682 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2683 if (ret == XML_CATAL_BREAK)
2684 ret = NULL;
2685 } else {
2686 const xmlChar *sgml;
2687
2688 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2689 if (sgml != NULL)
2690 sgml = xmlStrdup(sgml);
2691 }
2692 return(ret);
2693}
2694
2695/**
2696 * xmlACatalogDump:
2697 * @catal: a Catalog
2698 * @out: the file.
2699 *
2700 * Free up all the memory associated with catalogs
2701 */
2702void
2703xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
2704 if (out == NULL)
2705 return;
2706
2707 if (catal->type == XML_XML_CATALOG_TYPE) {
2708 xmlDumpXMLCatalog(out, catal->xml);
2709 } else {
2710 xmlHashScan(catal->sgml,
2711 (xmlHashScanner) xmlCatalogDumpEntry, out);
2712 }
2713}
2714
2715/**
2716 * xmlACatalogAdd:
2717 * @catal: a Catalog
2718 * @type: the type of record to add to the catalog
2719 * @orig: the system, public or prefix to match
2720 * @replace: the replacement value for the match
2721 *
2722 * Add an entry in the catalog, it may overwrite existing but
2723 * different entries.
2724 *
2725 * Returns 0 if successful, -1 otherwise
2726 */
2727int
2728xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2729 const xmlChar * orig, const xmlChar * replace)
2730{
2731 int res = -1;
2732
2733 if (catal == NULL)
2734 return(-1);
2735
2736 if (catal->type == XML_XML_CATALOG_TYPE) {
2737 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2738 } else {
2739 xmlCatalogEntryType cattype;
2740
2741 cattype = xmlGetSGMLCatalogEntryType(type);
2742 if (cattype != XML_CATA_NONE) {
2743 xmlCatalogEntryPtr entry;
2744
2745 entry = xmlNewCatalogEntry(cattype, orig, replace,
2746 XML_CATA_PREFER_NONE);
2747 res = xmlHashAddEntry(catal->sgml, orig, entry);
2748 }
2749 }
2750 return (res);
2751}
2752
2753/**
2754 * xmlACatalogRemove:
2755 * @catal: a Catalog
2756 * @value: the value to remove
2757 *
2758 * Remove an entry from the catalog
2759 *
2760 * Returns the number of entries removed if successful, -1 otherwise
2761 */
2762int
2763xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2764 int res = -1;
2765
2766 if ((catal == NULL) || (value == NULL))
2767 return(-1);
2768
2769 if (catal->type == XML_XML_CATALOG_TYPE) {
2770 res = xmlDelXMLCatalog(catal->xml, value);
2771 } else {
2772 res = xmlHashRemoveEntry(catal->sgml, value,
2773 (xmlHashDeallocator) xmlFreeCatalogEntry);
2774 if (res == 0)
2775 res = 1;
2776 }
2777 return(res);
2778}
2779
2780/************************************************************************
2781 * *
2782 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00002783 * *
2784 ************************************************************************/
2785
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002786/**
Daniel Veillard81463942001-10-16 12:34:39 +00002787 * xmlInitializeCatalogData:
2788 *
2789 * Do the catalog initialization only of global data, doesn't try to load
2790 * any catalog actually.
2791 * this function is not thread safe, catalog initialization should
2792 * preferably be done once at startup
2793 */
2794static void
2795xmlInitializeCatalogData(void) {
2796 if (xmlCatalogInitialized != 0)
2797 return;
2798
2799 if (getenv("XML_DEBUG_CATALOG"))
2800 xmlDebugCatalogs = 1;
2801 xmlCatalogMutex = xmlNewRMutex();
2802
2803 xmlCatalogInitialized = 1;
2804}
2805/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002806 * xmlInitializeCatalog:
2807 *
2808 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00002809 * this function is not thread safe, catalog initialization should
2810 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002811 */
2812void
2813xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002814 if (xmlCatalogInitialized != 0)
2815 return;
2816
Daniel Veillard81463942001-10-16 12:34:39 +00002817 xmlInitializeCatalogData();
2818 xmlRMutexLock(xmlCatalogMutex);
2819
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002820 if (getenv("XML_DEBUG_CATALOG"))
2821 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00002822
Daniel Veillard75b96822001-10-11 18:59:45 +00002823 if (xmlDefaultCatalog == NULL) {
2824 const char *catalogs;
2825 xmlCatalogPtr catal;
2826
Daniel Veillardb44025c2001-10-11 22:55:55 +00002827 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002828 if (catalogs == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002829 catalogs = XML_XML_DEFAULT_CATALOG;
2830
2831 catal = xmlNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002832 if (catal != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002833
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002834 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG,
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002835 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002836
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002837 xmlDefaultCatalog = catal;
2838 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002839 }
2840
Daniel Veillard81463942001-10-16 12:34:39 +00002841 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002842}
2843
Daniel Veillard82d75332001-10-08 15:01:59 +00002844
2845/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002846 * xmlLoadCatalog:
2847 * @filename: a file path
2848 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002849 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002850 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00002851 * this function is not thread safe, catalog initialization should
2852 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002853 *
2854 * Returns 0 in case of success -1 in case of error
2855 */
2856int
Daniel Veillard16756b62001-10-01 07:36:25 +00002857xmlLoadCatalog(const char *filename)
2858{
Daniel Veillard75b96822001-10-11 18:59:45 +00002859 int ret;
2860 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00002861
Daniel Veillard81463942001-10-16 12:34:39 +00002862 if (!xmlCatalogInitialized)
2863 xmlInitializeCatalogData();
2864
2865 xmlRMutexLock(xmlCatalogMutex);
2866
Daniel Veillard75b96822001-10-11 18:59:45 +00002867 if (xmlDefaultCatalog == NULL) {
2868 catal = xmlLoadACatalog(filename);
2869 if (catal == NULL)
2870 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002871
Daniel Veillard75b96822001-10-11 18:59:45 +00002872 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00002873 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002874 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002875 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002876
Daniel Veillard75b96822001-10-11 18:59:45 +00002877 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00002878 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00002879 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002880}
2881
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002882/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002883 * xmlLoadCatalogs:
2884 * @paths: a list of file path separated by ':' or spaces
2885 *
2886 * Load the catalogs and makes their definitions effective for the default
2887 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00002888 * this function is not thread safe, catalog initialization should
2889 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002890 */
2891void
2892xmlLoadCatalogs(const char *pathss) {
2893 const char *cur;
2894 const char *paths;
2895 xmlChar *path;
2896
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002897 if (pathss == NULL)
2898 return;
2899
Daniel Veillard81418e32001-05-22 15:08:55 +00002900 cur = pathss;
2901 while ((cur != NULL) && (*cur != 0)) {
2902 while (IS_BLANK(*cur)) cur++;
2903 if (*cur != 0) {
2904 paths = cur;
2905 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2906 cur++;
2907 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2908 if (path != NULL) {
2909 xmlLoadCatalog((const char *) path);
2910 xmlFree(path);
2911 }
2912 }
2913 while (*cur == ':')
2914 cur++;
2915 }
2916}
2917
Daniel Veillarda7374592001-05-10 14:17:55 +00002918/**
2919 * xmlCatalogCleanup:
2920 *
2921 * Free up all the memory associated with catalogs
2922 */
2923void
2924xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00002925 if (xmlCatalogInitialized == 0)
2926 return;
2927
Daniel Veillard81463942001-10-16 12:34:39 +00002928 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002929 if (xmlDebugCatalogs)
2930 xmlGenericError(xmlGenericErrorContext,
2931 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002932 if (xmlCatalogXMLFiles != NULL)
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002933 xmlHashFree(xmlCatalogXMLFiles,
2934 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002935 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002936 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002937 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002938 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002939 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002940 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00002941 xmlRMutexUnlock(xmlCatalogMutex);
2942 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00002943}
2944
2945/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002946 * xmlCatalogResolveSystem:
2947 * @sysId: the public ID string
2948 *
2949 * Try to lookup the catalog resource for a system ID
2950 *
2951 * Returns the system ID if found or NULL otherwise, the value returned
2952 * must be freed by the caller.
2953 */
2954xmlChar *
2955xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002956 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002957
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002958 if (!xmlCatalogInitialized)
2959 xmlInitializeCatalog();
2960
Daniel Veillard75b96822001-10-11 18:59:45 +00002961 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
2962 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002963}
2964
2965/**
2966 * xmlCatalogResolvePublic:
2967 * @pubId: the public ID string
2968 *
2969 * Try to lookup the system ID associated to a public ID
2970 *
2971 * Returns the system ID if found or NULL otherwise, the value returned
2972 * must be freed by the caller.
2973 */
2974xmlChar *
2975xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002976 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002977
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002978 if (!xmlCatalogInitialized)
2979 xmlInitializeCatalog();
2980
Daniel Veillard75b96822001-10-11 18:59:45 +00002981 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
2982 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002983}
Daniel Veillard344cee72001-08-20 00:08:40 +00002984
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002985/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002986 * xmlCatalogResolve:
2987 * @pubId: the public ID string
2988 * @sysId: the system ID string
2989 *
2990 * Do a complete resolution lookup of an External Identifier
2991 *
2992 * Returns the URI of the resource or NULL if not found, it must be freed
2993 * by the caller.
2994 */
2995xmlChar *
2996xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002997 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002998
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002999 if (!xmlCatalogInitialized)
3000 xmlInitializeCatalog();
3001
Daniel Veillard75b96822001-10-11 18:59:45 +00003002 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3003 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003004}
3005
3006/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003007 * xmlCatalogResolveURI:
3008 * @pubId: the URI
3009 *
3010 * Do a complete resolution lookup of an URI
3011 *
3012 * Returns the URI of the resource or NULL if not found, it must be freed
3013 * by the caller.
3014 */
3015xmlChar *
3016xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003017 xmlChar *ret;
3018
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003019 if (!xmlCatalogInitialized)
3020 xmlInitializeCatalog();
3021
Daniel Veillard75b96822001-10-11 18:59:45 +00003022 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3023 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003024}
3025
3026/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003027 * xmlCatalogDump:
3028 * @out: the file.
3029 *
3030 * Free up all the memory associated with catalogs
3031 */
3032void
3033xmlCatalogDump(FILE *out) {
3034 if (out == NULL)
3035 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003036
Daniel Veillard75b96822001-10-11 18:59:45 +00003037 if (!xmlCatalogInitialized)
3038 xmlInitializeCatalog();
3039
3040 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003041}
3042
3043/**
3044 * xmlCatalogAdd:
3045 * @type: the type of record to add to the catalog
3046 * @orig: the system, public or prefix to match
3047 * @replace: the replacement value for the match
3048 *
3049 * Add an entry in the catalog, it may overwrite existing but
3050 * different entries.
Daniel Veillard75b96822001-10-11 18:59:45 +00003051 * If called before any other catalo routine, allows to override the
3052 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003053 *
3054 * Returns 0 if successful, -1 otherwise
3055 */
3056int
3057xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3058 int res = -1;
3059
Daniel Veillard81463942001-10-16 12:34:39 +00003060 if (!xmlCatalogInitialized)
3061 xmlInitializeCatalogData();
3062
3063 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003064 /*
3065 * Specific case where one want to override the default catalog
3066 * put in place by xmlInitializeCatalog();
3067 */
3068 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003069 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003070 xmlDefaultCatalog = xmlNewCatalog(XML_XML_CATALOG_TYPE,
3071 xmlCatalogDefaultPrefer);
3072 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3073 orig, xmlCatalogDefaultPrefer);
3074
Daniel Veillard81463942001-10-16 12:34:39 +00003075 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003076 return(0);
3077 }
3078
Daniel Veillard75b96822001-10-11 18:59:45 +00003079 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003080 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003081 return(res);
3082}
3083
3084/**
3085 * xmlCatalogRemove:
3086 * @value: the value to remove
3087 *
3088 * Remove an entry from the catalog
3089 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003090 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003091 */
3092int
3093xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003094 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003095
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003096 if (!xmlCatalogInitialized)
3097 xmlInitializeCatalog();
3098
Daniel Veillard81463942001-10-16 12:34:39 +00003099 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003100 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003101 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003102 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003103}
3104
3105/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003106 * xmlCatalogConvert:
3107 *
3108 * Convert all the SGML catalog entries as XML ones
3109 *
3110 * Returns the number of entries converted if successful, -1 otherwise
3111 */
3112int
3113xmlCatalogConvert(void) {
3114 int res = -1;
3115
3116 if (!xmlCatalogInitialized)
3117 xmlInitializeCatalog();
3118
Daniel Veillard81463942001-10-16 12:34:39 +00003119 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003120 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003121 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003122 return(res);
3123}
3124
Daniel Veillard75b96822001-10-11 18:59:45 +00003125/************************************************************************
3126 * *
3127 * Public interface manipulating the common preferences *
3128 * *
3129 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003130
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003131/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003132 * xmlCatalogGetDefaults:
3133 *
3134 * Used to get the user preference w.r.t. to what catalogs should
3135 * be accepted
3136 *
3137 * Returns the current xmlCatalogAllow value
3138 */
3139xmlCatalogAllow
3140xmlCatalogGetDefaults(void) {
3141 return(xmlCatalogDefaultAllow);
3142}
3143
3144/**
3145 * xmlCatalogSetDefaults:
3146 *
3147 * Used to set the user preference w.r.t. to what catalogs should
3148 * be accepted
3149 */
3150void
3151xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003152 if (xmlDebugCatalogs) {
3153 switch (allow) {
3154 case XML_CATA_ALLOW_NONE:
3155 xmlGenericError(xmlGenericErrorContext,
3156 "Disabling catalog usage\n");
3157 break;
3158 case XML_CATA_ALLOW_GLOBAL:
3159 xmlGenericError(xmlGenericErrorContext,
3160 "Allowing only global catalogs\n");
3161 break;
3162 case XML_CATA_ALLOW_DOCUMENT:
3163 xmlGenericError(xmlGenericErrorContext,
3164 "Allowing only catalogs from the document\n");
3165 break;
3166 case XML_CATA_ALLOW_ALL:
3167 xmlGenericError(xmlGenericErrorContext,
3168 "Allowing all catalogs\n");
3169 break;
3170 }
3171 }
3172 xmlCatalogDefaultAllow = allow;
3173}
3174
3175/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003176 * xmlCatalogSetDefaultPrefer:
3177 * @prefer: the default preference for delegation
3178 *
3179 * Allows to set the preference between public and system for deletion
3180 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003181 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003182 *
3183 * Returns the previous value of the default preference for delegation
3184 */
3185xmlCatalogPrefer
3186xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3187 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3188
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003189 if (prefer == XML_CATA_PREFER_NONE)
3190 return(ret);
3191
3192 if (xmlDebugCatalogs) {
3193 switch (prefer) {
3194 case XML_CATA_PREFER_PUBLIC:
3195 xmlGenericError(xmlGenericErrorContext,
3196 "Setting catalog preference to PUBLIC\n");
3197 break;
3198 case XML_CATA_PREFER_SYSTEM:
3199 xmlGenericError(xmlGenericErrorContext,
3200 "Setting catalog preference to SYSTEM\n");
3201 break;
3202 case XML_CATA_PREFER_NONE:
3203 break;
3204 }
3205 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003206 xmlCatalogDefaultPrefer = prefer;
3207 return(ret);
3208}
3209
3210/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003211 * xmlCatalogSetDebug:
3212 * @level: the debug level of catalogs required
3213 *
3214 * Used to set the debug level for catalog operation, 0 disable
3215 * debugging, 1 enable it
3216 *
3217 * Returns the previous value of the catalog debugging level
3218 */
3219int
3220xmlCatalogSetDebug(int level) {
3221 int ret = xmlDebugCatalogs;
3222
3223 if (level <= 0)
3224 xmlDebugCatalogs = 0;
3225 else
3226 xmlDebugCatalogs = level;
3227 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003228}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003229
Daniel Veillard75b96822001-10-11 18:59:45 +00003230/************************************************************************
3231 * *
3232 * Minimal interfaces used for per-document catalogs by the parser *
3233 * *
3234 ************************************************************************/
3235
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003236/**
3237 * xmlCatalogFreeLocal:
3238 * @catalogs: a document's list of catalogs
3239 *
3240 * Free up the memory associated to the catalog list
3241 */
3242void
3243xmlCatalogFreeLocal(void *catalogs) {
3244 xmlCatalogEntryPtr catal;
3245
Daniel Veillard81463942001-10-16 12:34:39 +00003246 if (!xmlCatalogInitialized)
3247 xmlInitializeCatalog();
3248
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003249 catal = (xmlCatalogEntryPtr) catalogs;
3250 if (catal != NULL)
3251 xmlFreeCatalogEntryList(catal);
3252}
3253
3254
3255/**
3256 * xmlCatalogAddLocal:
3257 * @catalogs: a document's list of catalogs
3258 * @URL: the URL to a new local catalog
3259 *
3260 * Add the new entry to the catalog list
3261 *
3262 * Returns the updated list
3263 */
3264void *
3265xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3266 xmlCatalogEntryPtr catal, add;
3267
3268 if (!xmlCatalogInitialized)
3269 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003270
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003271 if (URL == NULL)
3272 return(catalogs);
3273
3274 if (xmlDebugCatalogs)
3275 xmlGenericError(xmlGenericErrorContext,
3276 "Adding document catalog %s\n", URL);
3277
3278 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
3279 xmlCatalogDefaultPrefer);
3280 if (add == NULL)
3281 return(catalogs);
3282
3283 catal = (xmlCatalogEntryPtr) catalogs;
3284 if (catal == NULL)
3285 return((void *) add);
3286
3287 while (catal->next != NULL)
3288 catal = catal->next;
3289 catal->next = add;
3290 return(catalogs);
3291}
3292
3293/**
3294 * xmlCatalogLocalResolve:
3295 * @catalogs: a document's list of catalogs
3296 * @pubId: the public ID string
3297 * @sysId: the system ID string
3298 *
3299 * Do a complete resolution lookup of an External Identifier using a
3300 * document's private catalog list
3301 *
3302 * Returns the URI of the resource or NULL if not found, it must be freed
3303 * by the caller.
3304 */
3305xmlChar *
3306xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3307 const xmlChar *sysID) {
3308 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003309 xmlChar *ret;
3310
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003311 if (!xmlCatalogInitialized)
3312 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003313
Daniel Veillard81463942001-10-16 12:34:39 +00003314 if ((pubID == NULL) && (sysID == NULL))
3315 return(NULL);
3316
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003317 if (xmlDebugCatalogs) {
3318 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003319 xmlGenericError(xmlGenericErrorContext,
3320 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003321 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003322 xmlGenericError(xmlGenericErrorContext,
3323 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003324 }
3325 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003326
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003327 catal = (xmlCatalogEntryPtr) catalogs;
3328 if (catal == NULL)
3329 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003330 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3331 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3332 return(ret);
3333 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003334}
3335
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003336/**
3337 * xmlCatalogLocalResolveURI:
3338 * @catalogs: a document's list of catalogs
3339 * @pubId: the URI
3340 *
3341 * Do a complete resolution lookup of an URI using a
3342 * document's private catalog list
3343 *
3344 * Returns the URI of the resource or NULL if not found, it must be freed
3345 * by the caller.
3346 */
3347xmlChar *
3348xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3349 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003350 xmlChar *ret;
3351
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003352 if (!xmlCatalogInitialized)
3353 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003354
Daniel Veillard81463942001-10-16 12:34:39 +00003355 if (URI == NULL)
3356 return(NULL);
3357
Daniel Veillard6990bf32001-08-23 21:17:48 +00003358 if (xmlDebugCatalogs)
3359 xmlGenericError(xmlGenericErrorContext,
3360 "Resolve URI %s\n", URI);
3361
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003362 catal = (xmlCatalogEntryPtr) catalogs;
3363 if (catal == NULL)
3364 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003365 ret = xmlCatalogListXMLResolveURI(catal, URI);
3366 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3367 return(ret);
3368 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003369}
3370
Daniel Veillard75b96822001-10-11 18:59:45 +00003371/************************************************************************
3372 * *
3373 * Deprecated interfaces *
3374 * *
3375 ************************************************************************/
3376/**
3377 * xmlCatalogGetSystem:
3378 * @pubId: the public ID string
3379 *
3380 * Try to lookup the system ID associated to a public ID
3381 * DEPRECATED, use xmlCatalogResolveSystem()
3382 *
3383 * Returns the system ID if found or NULL otherwise.
3384 */
3385const xmlChar *
3386xmlCatalogGetSystem(const xmlChar *sysID) {
3387 xmlChar *ret;
3388 static xmlChar result[1000];
3389 static int msg = 0;
3390
Daniel Veillard81463942001-10-16 12:34:39 +00003391 if (!xmlCatalogInitialized)
3392 xmlInitializeCatalog();
3393
Daniel Veillard75b96822001-10-11 18:59:45 +00003394 if (msg == 0) {
3395 xmlGenericError(xmlGenericErrorContext,
3396 "Use of deprecated xmlCatalogGetSystem() call\n");
3397 msg++;
3398 }
3399
3400 if (sysID == NULL)
3401 return(NULL);
3402
Daniel Veillard75b96822001-10-11 18:59:45 +00003403 /*
3404 * Check first the XML catalogs
3405 */
3406 if (xmlDefaultCatalog != NULL) {
3407 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3408 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3409 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3410 result[sizeof(result) - 1] = 0;
3411 return(result);
3412 }
3413 }
3414
3415 if (xmlDefaultCatalog != NULL)
3416 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3417 return(NULL);
3418}
3419
3420/**
3421 * xmlCatalogGetPublic:
3422 * @pubId: the public ID string
3423 *
3424 * Try to lookup the system ID associated to a public ID
3425 * DEPRECATED, use xmlCatalogResolvePublic()
3426 *
3427 * Returns the system ID if found or NULL otherwise.
3428 */
3429const xmlChar *
3430xmlCatalogGetPublic(const xmlChar *pubID) {
3431 xmlChar *ret;
3432 static xmlChar result[1000];
3433 static int msg = 0;
3434
Daniel Veillard81463942001-10-16 12:34:39 +00003435 if (!xmlCatalogInitialized)
3436 xmlInitializeCatalog();
3437
Daniel Veillard75b96822001-10-11 18:59:45 +00003438 if (msg == 0) {
3439 xmlGenericError(xmlGenericErrorContext,
3440 "Use of deprecated xmlCatalogGetPublic() call\n");
3441 msg++;
3442 }
3443
3444 if (pubID == NULL)
3445 return(NULL);
3446
Daniel Veillard75b96822001-10-11 18:59:45 +00003447 /*
3448 * Check first the XML catalogs
3449 */
3450 if (xmlDefaultCatalog != NULL) {
3451 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3452 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3453 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3454 result[sizeof(result) - 1] = 0;
3455 return(result);
3456 }
3457 }
3458
3459 if (xmlDefaultCatalog != NULL)
3460 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3461 return(NULL);
3462}
3463
Daniel Veillarda7374592001-05-10 14:17:55 +00003464#endif /* LIBXML_CATALOG_ENABLED */