blob: 06b2b53bb0fff82114808685f150f44fbbfca6c3 [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
30#include <string.h>
31#include <libxml/xmlmemory.h>
32#include <libxml/hash.h>
33#include <libxml/uri.h>
34#include <libxml/parserInternals.h>
35#include <libxml/catalog.h>
36#include <libxml/xmlerror.h>
37
Daniel Veillard344cee72001-08-20 00:08:40 +000038/**
39 * TODO:
40 *
41 * macro to flag unimplemented blocks
42 */
43#define TODO \
44 xmlGenericError(xmlGenericErrorContext, \
45 "Unimplemented block at %s:%d\n", \
46 __FILE__, __LINE__);
47
Daniel Veillardcda96922001-08-21 10:56:31 +000048#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000049#define XML_CATAL_BREAK ((xmlChar *) -1)
50#define XML_DEFAULT_CATALOG "/etc/xml/catalog"
Daniel Veillard344cee72001-08-20 00:08:40 +000051
Daniel Veillarda7374592001-05-10 14:17:55 +000052/************************************************************************
53 * *
54 * Types, all private *
55 * *
56 ************************************************************************/
57
58typedef enum {
59 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000060 XML_CATA_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000061 XML_CATA_NEXT_CATALOG,
62 XML_CATA_PUBLIC,
63 XML_CATA_SYSTEM,
64 XML_CATA_REWRITE_SYSTEM,
65 XML_CATA_DELEGATE_PUBLIC,
66 XML_CATA_DELEGATE_SYSTEM,
67 XML_CATA_URI,
68 XML_CATA_REWRITE_URI,
69 XML_CATA_DELEGATE_URI,
70 SGML_CATA_SYSTEM,
71 SGML_CATA_PUBLIC,
72 SGML_CATA_ENTITY,
73 SGML_CATA_PENTITY,
74 SGML_CATA_DOCTYPE,
75 SGML_CATA_LINKTYPE,
76 SGML_CATA_NOTATION,
77 SGML_CATA_DELEGATE,
78 SGML_CATA_BASE,
79 SGML_CATA_CATALOG,
80 SGML_CATA_DOCUMENT,
81 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000082} xmlCatalogEntryType;
83
84typedef struct _xmlCatalogEntry xmlCatalogEntry;
85typedef xmlCatalogEntry *xmlCatalogEntryPtr;
86struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +000087 struct _xmlCatalogEntry *next;
88 struct _xmlCatalogEntry *parent;
89 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +000090 xmlCatalogEntryType type;
91 xmlChar *name;
92 xmlChar *value;
Daniel Veillarde2940dd2001-08-22 00:06:49 +000093 xmlCatalogPrefer prefer;
Daniel Veillarda7374592001-05-10 14:17:55 +000094};
95
Daniel Veillard5d90b6c2001-08-22 14:29:45 +000096static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
97static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +000098static xmlHashTablePtr xmlDefaultCatalog;
Daniel Veillard344cee72001-08-20 00:08:40 +000099static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000100static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000101
Daniel Veillarda7374592001-05-10 14:17:55 +0000102
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000103/* Catalog stack */
Daniel Veillard81418e32001-05-22 15:08:55 +0000104static const char * catalTab[10]; /* stack of catals */
105static int catalNr = 0; /* Number of current catal streams */
106static int catalMax = 10; /* Max number of catal streams */
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000107
Daniel Veillard344cee72001-08-20 00:08:40 +0000108static int xmlDebugCatalogs = 0; /* used for debugging */
109
Daniel Veillarda7374592001-05-10 14:17:55 +0000110/************************************************************************
111 * *
112 * alloc or dealloc *
113 * *
114 ************************************************************************/
115
116static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000117xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000118 const xmlChar *value, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000119 xmlCatalogEntryPtr ret;
120
121 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
122 if (ret == NULL) {
123 xmlGenericError(xmlGenericErrorContext,
124 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
125 return(NULL);
126 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000127 ret->next = NULL;
128 ret->parent = NULL;
129 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000130 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000131 if (name != NULL)
132 ret->name = xmlStrdup(name);
133 else
134 ret->name = NULL;
135 if (value != NULL)
136 ret->value = xmlStrdup(value);
137 else
138 ret->value = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000139 ret->prefer = prefer;
Daniel Veillarda7374592001-05-10 14:17:55 +0000140 return(ret);
141}
142
143static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000144xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
145
146static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000147xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
148 if (ret == NULL)
149 return;
Daniel Veillard344cee72001-08-20 00:08:40 +0000150 if (ret->children != NULL)
151 xmlFreeCatalogEntryList(ret->children);
Daniel Veillarda7374592001-05-10 14:17:55 +0000152 if (ret->name != NULL)
153 xmlFree(ret->name);
154 if (ret->value != NULL)
155 xmlFree(ret->value);
156 xmlFree(ret);
157}
158
Daniel Veillard344cee72001-08-20 00:08:40 +0000159static void
160xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
161 xmlCatalogEntryPtr next;
162
163 while (ret != NULL) {
164 next = ret->next;
165 xmlFreeCatalogEntry(ret);
166 ret = next;
167 }
168}
169
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000170/**
171 * xmlCatalogDumpEntry:
172 * @entry: the
173 * @out: the file.
174 *
175 * Free up all the memory associated with catalogs
176 */
177static void
178xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
179 if ((entry == NULL) || (out == NULL))
180 return;
181 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000182 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000183 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000184 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000185 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000186 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000187 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000188 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000189 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000190 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000191 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000192 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000193 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000194 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000195 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000196 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000197 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000198 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000199 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000200 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000201 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000202 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000203 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000204 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000205 fprintf(out, "SGMLDECL "); break;
206 default:
207 return;
208 }
209 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000210 case SGML_CATA_ENTITY:
211 case SGML_CATA_PENTITY:
212 case SGML_CATA_DOCTYPE:
213 case SGML_CATA_LINKTYPE:
214 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000215 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000216 case SGML_CATA_PUBLIC:
217 case SGML_CATA_SYSTEM:
218 case SGML_CATA_SGMLDECL:
219 case SGML_CATA_DOCUMENT:
220 case SGML_CATA_CATALOG:
221 case SGML_CATA_BASE:
222 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000223 fprintf(out, "\"%s\"", entry->name); break;
224 default:
225 break;
226 }
227 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000228 case SGML_CATA_ENTITY:
229 case SGML_CATA_PENTITY:
230 case SGML_CATA_DOCTYPE:
231 case SGML_CATA_LINKTYPE:
232 case SGML_CATA_NOTATION:
233 case SGML_CATA_PUBLIC:
234 case SGML_CATA_SYSTEM:
235 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000236 fprintf(out, " \"%s\"", entry->value); break;
237 default:
238 break;
239 }
240 fprintf(out, "\n");
241}
242
Daniel Veillarda7374592001-05-10 14:17:55 +0000243/************************************************************************
244 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000245 * Helper function *
246 * *
247 ************************************************************************/
248
249/**
250 * xmlCatalogUnWrapURN:
251 * @urn: an "urn:publicid:" to unwrapp
252 *
253 * Expand the URN into the equivalent Public Identifier
254 *
255 * Returns the new identifier or NULL, the string must be deallocated
256 * by the caller.
257 */
258static xmlChar *
259xmlCatalogUnWrapURN(const xmlChar *urn) {
260 xmlChar result[2000];
261 unsigned int i = 0;
262
263 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
264 return(NULL);
265 urn += sizeof(XML_URN_PUBID) - 1;
266
267 while (*urn != 0) {
268 if (i > sizeof(result) - 3)
269 break;
270 if (*urn == '+') {
271 result[i++] = ' ';
272 urn++;
273 } else if (*urn == ':') {
274 result[i++] = '/';
275 result[i++] = '/';
276 urn++;
277 } else if (*urn == ';') {
278 result[i++] = ':';
279 result[i++] = ':';
280 urn++;
281 } else if (*urn == '%') {
282 if ((urn[1] == '2') && (urn[1] == 'B'))
283 result[i++] = '+';
284 else if ((urn[1] == '3') && (urn[1] == 'A'))
285 result[i++] = ':';
286 else if ((urn[1] == '2') && (urn[1] == 'F'))
287 result[i++] = '/';
288 else if ((urn[1] == '3') && (urn[1] == 'B'))
289 result[i++] = ';';
290 else if ((urn[1] == '2') && (urn[1] == '7'))
291 result[i++] = '\'';
292 else if ((urn[1] == '3') && (urn[1] == 'F'))
293 result[i++] = '?';
294 else if ((urn[1] == '2') && (urn[1] == '3'))
295 result[i++] = '#';
296 else if ((urn[1] == '2') && (urn[1] == '5'))
297 result[i++] = '%';
298 else {
299 result[i++] = *urn;
300 urn++;
301 continue;
302 }
303 urn += 3;
304 } else {
305 result[i++] = *urn;
306 urn++;
307 }
308 }
309 result[i] = 0;
310
311 return(xmlStrdup(result));
312}
313
314/************************************************************************
315 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000316 * The XML Catalog parser *
317 * *
318 ************************************************************************/
319
320static xmlCatalogEntryPtr
321xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
322
323static xmlCatalogEntryPtr
324xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
325 const char *file);
326static void
327xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
328 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000329static xmlChar *
330xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
331 const xmlChar *sysID);
Daniel Veillard344cee72001-08-20 00:08:40 +0000332
333static xmlCatalogEntryType
334xmlGetXMLCatalogEntryType(const xmlChar *name) {
335 xmlCatalogEntryType type = XML_CATA_NONE;
336 if (xmlStrEqual(name, (const xmlChar *) "system"))
337 type = XML_CATA_SYSTEM;
338 else if (xmlStrEqual(name, (const xmlChar *) "public"))
339 type = XML_CATA_PUBLIC;
340 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
341 type = XML_CATA_REWRITE_SYSTEM;
342 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
343 type = XML_CATA_DELEGATE_PUBLIC;
344 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
345 type = XML_CATA_DELEGATE_SYSTEM;
346 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
347 type = XML_CATA_URI;
348 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
349 type = XML_CATA_REWRITE_URI;
350 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
351 type = XML_CATA_DELEGATE_URI;
352 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
353 type = XML_CATA_NEXT_CATALOG;
354 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
355 type = XML_CATA_CATALOG;
356 return(type);
357}
358
359static xmlCatalogEntryPtr
360xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
361 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000362 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000363 int ok = 1;
364 xmlChar *uriValue;
365 xmlChar *nameValue = NULL;
366 xmlChar *base = NULL;
367 xmlChar *URL = NULL;
368 xmlCatalogEntryPtr ret = NULL;
369
370 if (attrName != NULL) {
371 nameValue = xmlGetProp(cur, attrName);
372 if (nameValue == NULL) {
373 xmlGenericError(xmlGenericErrorContext,
374 "%s entry lacks '%s'\n", name, attrName);
375 ok = 0;
376 }
377 }
378 uriValue = xmlGetProp(cur, uriAttrName);
379 if (uriValue == NULL) {
380 xmlGenericError(xmlGenericErrorContext,
381 "%s entry lacks '%s'\n", name, uriAttrName);
382 ok = 0;
383 }
384 if (!ok) {
385 if (nameValue != NULL)
386 xmlFree(nameValue);
387 if (uriValue != NULL)
388 xmlFree(uriValue);
389 return(NULL);
390 }
391
392 base = xmlNodeGetBase(cur->doc, cur);
393 URL = xmlBuildURI(uriValue, base);
394 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000395 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000396 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000397 xmlGenericError(xmlGenericErrorContext,
398 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000399 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000400 xmlGenericError(xmlGenericErrorContext,
401 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000402 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000403 ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000404 } else {
405 xmlGenericError(xmlGenericErrorContext,
406 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
407 }
408 if (nameValue != NULL)
409 xmlFree(nameValue);
410 if (uriValue != NULL)
411 xmlFree(uriValue);
412 if (base != NULL)
413 xmlFree(base);
414 if (URL != NULL)
415 xmlFree(URL);
416 return(ret);
417}
418
419static void
420xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
421 xmlCatalogEntryPtr parent)
422{
423 xmlChar *uri = NULL;
424 xmlChar *URL = NULL;
425 xmlChar *base = NULL;
426 xmlCatalogEntryPtr entry = NULL;
427
428 if (cur == NULL)
429 return;
430 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
431 xmlChar *prop;
432
433 prop = xmlGetProp(cur, BAD_CAST "prefer");
434 if (prop != NULL) {
435 if (xmlStrEqual(prop, BAD_CAST "system")) {
436 prefer = XML_CATA_PREFER_SYSTEM;
437 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
438 prefer = XML_CATA_PREFER_PUBLIC;
439 } else {
440 xmlGenericError(xmlGenericErrorContext,
441 "Invalid value for prefer: '%s'\n", prop);
442 }
443 xmlFree(prop);
444 }
445 /*
446 * Recurse to propagate prefer to the subtree
447 * (xml:base handling is automated)
448 */
449 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
450 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
451 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000452 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000453 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
454 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000455 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000456 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
457 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
458 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000459 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000460 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
461 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
462 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000463 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000464 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
465 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
466 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000467 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000468 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
469 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
470 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000471 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000472 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
473 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
474 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000475 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000476 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
477 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
478 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000479 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000480 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
481 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
482 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000483 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000484 }
485 if ((entry != NULL) && (parent != NULL)) {
486 entry->parent = parent;
487 if (parent->children == NULL)
488 parent->children = entry;
489 else {
490 xmlCatalogEntryPtr prev;
491
492 prev = parent->children;
493 while (prev->next != NULL)
494 prev = prev->next;
495 prev->next = entry;
496 }
497 }
498 if (base != NULL)
499 xmlFree(base);
500 if (uri != NULL)
501 xmlFree(uri);
502 if (URL != NULL)
503 xmlFree(URL);
504}
505
506static void
507xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
508 xmlCatalogEntryPtr parent) {
509 while (cur != NULL) {
510 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
511 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
512 xmlParseXMLCatalogNode(cur, prefer, parent);
513 }
514 cur = cur->next;
515 }
516 /* TODO: sort the list according to REWRITE lengths and prefer value */
517}
518
519static xmlCatalogEntryPtr
520xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
521 const char *file) {
522 xmlDocPtr doc;
523 xmlNodePtr cur;
524 xmlChar *prop;
525 xmlCatalogEntryPtr parent = NULL;
526
527 if ((value == NULL) || (file == NULL))
528 return(NULL);
529
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000530 if (xmlDebugCatalogs)
531 xmlGenericError(xmlGenericErrorContext,
532 "Parsing catalog %s's content\n", file);
533
Daniel Veillard344cee72001-08-20 00:08:40 +0000534 doc = xmlParseDoc((xmlChar *) value);
535 if (doc == NULL)
536 return(NULL);
537 doc->URL = xmlStrdup((const xmlChar *) file);
538
539 cur = xmlDocGetRootElement(doc);
540 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
541 (cur->ns != NULL) && (cur->ns->href != NULL) &&
542 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
543
Daniel Veillard344cee72001-08-20 00:08:40 +0000544 prop = xmlGetProp(cur, BAD_CAST "prefer");
545 if (prop != NULL) {
546 if (xmlStrEqual(prop, BAD_CAST "system")) {
547 prefer = XML_CATA_PREFER_SYSTEM;
548 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
549 prefer = XML_CATA_PREFER_PUBLIC;
550 } else {
551 xmlGenericError(xmlGenericErrorContext,
552 "Invalid value for prefer: '%s'\n",
553 prop);
554 }
555 xmlFree(prop);
556 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000557 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
558 (const xmlChar *)file, prefer);
559 if (parent == NULL) {
560 xmlFreeDoc(doc);
561 return(NULL);
562 }
563
Daniel Veillard344cee72001-08-20 00:08:40 +0000564 cur = cur->children;
565 xmlParseXMLCatalogNodeList(cur, prefer, parent);
566 } else {
567 xmlGenericError(xmlGenericErrorContext,
568 "File %s is not an XML Catalog\n", file);
569 xmlFreeDoc(doc);
570 return(NULL);
571 }
572 xmlFreeDoc(doc);
573 return(parent);
574}
575
576static xmlCatalogEntryPtr
577xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
578 xmlDocPtr doc;
579 xmlNodePtr cur;
580 xmlChar *prop;
581 xmlCatalogEntryPtr parent = NULL;
582
583 if (filename == NULL)
584 return(NULL);
585
586 doc = xmlParseFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000587 if (doc == NULL) {
588 if (xmlDebugCatalogs)
589 xmlGenericError(xmlGenericErrorContext,
590 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000591 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000592 }
593
594 if (xmlDebugCatalogs)
595 xmlGenericError(xmlGenericErrorContext,
596 "Parsing catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000597
598 cur = xmlDocGetRootElement(doc);
599 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
600 (cur->ns != NULL) && (cur->ns->href != NULL) &&
601 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
602
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000603 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
604 (const xmlChar *)filename, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000605 if (parent == NULL) {
606 xmlFreeDoc(doc);
607 return(NULL);
608 }
609
610 prop = xmlGetProp(cur, BAD_CAST "prefer");
611 if (prop != NULL) {
612 if (xmlStrEqual(prop, BAD_CAST "system")) {
613 prefer = XML_CATA_PREFER_SYSTEM;
614 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
615 prefer = XML_CATA_PREFER_PUBLIC;
616 } else {
617 xmlGenericError(xmlGenericErrorContext,
618 "Invalid value for prefer: '%s'\n",
619 prop);
620 }
621 xmlFree(prop);
622 }
623 cur = cur->children;
624 xmlParseXMLCatalogNodeList(cur, prefer, parent);
625 } else {
626 xmlGenericError(xmlGenericErrorContext,
627 "File %s is not an XML Catalog\n", filename);
628 xmlFreeDoc(doc);
629 return(NULL);
630 }
631 xmlFreeDoc(doc);
632 return(parent);
633}
634
Daniel Veillardcda96922001-08-21 10:56:31 +0000635/**
636 * xmlFetchXMLCatalogFile:
637 * @catal: an existing but incomplete catalog entry
638 *
639 * Fetch and parse the subcatalog referenced by an entry
640 * It tries to be thread safe but by lack of an atomic test and
641 * set there is a risk of loosing memory.
642 *
643 * Returns 0 in case of success, -1 otherwise
644 */
645static int
646xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
647 xmlCatalogEntryPtr children;
648
649 if (catal == NULL)
650 return(-1);
651 if (catal->value == NULL)
652 return(-1);
653 if (catal->children != NULL)
654 return(-1);
655
656 /*
657 * Fetch and parse
658 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000659 children = xmlParseXMLCatalogFile(catal->prefer, catal->value);
Daniel Veillardcda96922001-08-21 10:56:31 +0000660 if (children == NULL)
661 return(-1);
662
663 /*
664 * Where a real test and set would be needed !
665 */
666 if (catal->children == NULL) {
667 catal->children = children;
668 } else {
669 /*
670 * Another thread filled it before us
671 */
672 xmlFreeCatalogEntryList(children);
673 }
674 return(0);
675}
676
Daniel Veillard344cee72001-08-20 00:08:40 +0000677static int
678xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
679 int ret;
680 xmlDocPtr doc;
681 xmlNsPtr ns;
682 xmlDtdPtr dtd;
683 xmlNodePtr node, catalog;
684 xmlOutputBufferPtr buf;
685 xmlCatalogEntryPtr cur;
686
687 /*
688 * Rebuild a catalog
689 */
690 doc = xmlNewDoc(NULL);
691 if (doc == NULL)
692 return(-1);
693 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
694 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
695BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
696
697 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
698
699 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
700 if (ns == NULL) {
701 xmlFreeDoc(doc);
702 return(-1);
703 }
704 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
705 if (catalog == NULL) {
706 xmlFreeNs(ns);
707 xmlFreeDoc(doc);
708 return(-1);
709 }
710 catalog->nsDef = ns;
711 xmlAddChild((xmlNodePtr) doc, catalog);
712
713 /*
714 * add all the catalog entries
715 */
716 cur = catal;
717 while (cur != NULL) {
718 switch (cur->type) {
719 case XML_CATA_CATALOG:
720 if (cur == catal) {
721 cur = cur->children;
722 continue;
723 }
724 break;
725 case XML_CATA_NEXT_CATALOG:
726 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
727 xmlSetProp(node, BAD_CAST "catalog", cur->value);
728 xmlAddChild(catalog, node);
729 break;
730 case XML_CATA_NONE:
731 break;
732 case XML_CATA_PUBLIC:
733 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
734 xmlSetProp(node, BAD_CAST "publicId", cur->name);
735 xmlSetProp(node, BAD_CAST "uri", cur->value);
736 xmlAddChild(catalog, node);
737 break;
738 case XML_CATA_SYSTEM:
739 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
740 xmlSetProp(node, BAD_CAST "systemId", cur->name);
741 xmlSetProp(node, BAD_CAST "uri", cur->value);
742 xmlAddChild(catalog, node);
743 break;
744 case XML_CATA_REWRITE_SYSTEM:
745 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
746 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
747 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
748 xmlAddChild(catalog, node);
749 break;
750 case XML_CATA_DELEGATE_PUBLIC:
751 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
752 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
753 xmlSetProp(node, BAD_CAST "catalog", cur->value);
754 xmlAddChild(catalog, node);
755 break;
756 case XML_CATA_DELEGATE_SYSTEM:
757 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
758 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
759 xmlSetProp(node, BAD_CAST "catalog", cur->value);
760 xmlAddChild(catalog, node);
761 break;
762 case XML_CATA_URI:
763 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
764 xmlSetProp(node, BAD_CAST "name", cur->name);
765 xmlSetProp(node, BAD_CAST "uri", cur->value);
766 xmlAddChild(catalog, node);
767 break;
768 case XML_CATA_REWRITE_URI:
769 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
770 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
771 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
772 xmlAddChild(catalog, node);
773 break;
774 case XML_CATA_DELEGATE_URI:
775 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
776 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
777 xmlSetProp(node, BAD_CAST "catalog", cur->value);
778 xmlAddChild(catalog, node);
779 break;
780 case SGML_CATA_SYSTEM:
781 case SGML_CATA_PUBLIC:
782 case SGML_CATA_ENTITY:
783 case SGML_CATA_PENTITY:
784 case SGML_CATA_DOCTYPE:
785 case SGML_CATA_LINKTYPE:
786 case SGML_CATA_NOTATION:
787 case SGML_CATA_DELEGATE:
788 case SGML_CATA_BASE:
789 case SGML_CATA_CATALOG:
790 case SGML_CATA_DOCUMENT:
791 case SGML_CATA_SGMLDECL:
792 break;
793 }
794 cur = cur->next;
795 }
796
797 /*
798 * reserialize it
799 */
800 buf = xmlOutputBufferCreateFile(out, NULL);
801 if (buf == NULL) {
802 xmlFreeDoc(doc);
803 return(-1);
804 }
805 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
806
807 /*
808 * Free it
809 */
810 xmlFreeDoc(doc);
811
812 return(ret);
813}
814
815/**
816 * xmlAddXMLCatalog:
817 * @catal: top of an XML catalog
818 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +0000819 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +0000820 * @replace: the replacement value for the match
821 *
822 * Add an entry in the XML catalog, it may overwrite existing but
823 * different entries.
824 *
825 * Returns 0 if successful, -1 otherwise
826 */
827static int
828xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
829 const xmlChar *orig, const xmlChar *replace) {
830 xmlCatalogEntryPtr cur;
831 xmlCatalogEntryType typ;
832
833 if ((catal == NULL) || (catal->type != XML_CATA_CATALOG))
834 return(-1);
835 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000836 if (typ == XML_CATA_NONE) {
837 if (xmlDebugCatalogs)
838 xmlGenericError(xmlGenericErrorContext,
839 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +0000840 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000841 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000842
843 cur = catal->children;
844 /*
845 * Might be a simple "update in place"
846 */
847 if (cur != NULL) {
848 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000849 if ((orig != NULL) && (cur->type == typ) &&
850 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000851 if (xmlDebugCatalogs)
852 xmlGenericError(xmlGenericErrorContext,
853 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +0000854 if (cur->value != NULL)
855 xmlFree(cur->value);
856 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +0000857 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +0000858 }
859 if (cur->next == NULL)
860 break;
861 cur = cur->next;
862 }
863 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000864 if (xmlDebugCatalogs)
865 xmlGenericError(xmlGenericErrorContext,
866 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +0000867 if (cur == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000868 catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000869 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000870 cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillardcda96922001-08-21 10:56:31 +0000871 return(0);
872}
873
874/**
875 * xmlDelXMLCatalog:
876 * @catal: top of an XML catalog
877 * @value: the value to remove from teh catalog
878 *
879 * Remove entries in the XML catalog where the value or the URI
880 * is equal to @value
881 *
882 * Returns the number of entries removed if successful, -1 otherwise
883 */
884static int
885xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
886 xmlCatalogEntryPtr cur, prev, tmp;
887 int ret = 0;
888
889 if ((catal == NULL) || (catal->type != XML_CATA_CATALOG))
890 return(-1);
891 if (value == NULL)
892 return(-1);
893
894 /*
895 * Scan the children
896 */
897 cur = catal->children;
898 prev = NULL;
899 while (cur != NULL) {
900 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
901 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000902 if (xmlDebugCatalogs) {
903 if (cur->name != NULL)
904 xmlGenericError(xmlGenericErrorContext,
905 "Removing element %s from catalog\n", cur->name);
906 else
907 xmlGenericError(xmlGenericErrorContext,
908 "Removing element %s from catalog\n", cur->value);
909 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000910 ret++;
911 tmp = cur;
912 cur = tmp->next;
913 if (prev == NULL) {
914 catal->children = cur;
915 } else {
916 prev->next = cur;
917 }
918 xmlFreeCatalogEntry(tmp);
919 continue;
920 }
921 prev = cur;
922 cur = cur->next;
923 }
924 return(ret);
925}
926
927/**
Daniel Veillardcda96922001-08-21 10:56:31 +0000928 * xmlCatalogXMLResolve:
929 * @catal: a catalog list
930 * @pubId: the public ID string
931 * @sysId: the system ID string
932 *
933 * Do a complete resolution lookup of an External Identifier for a
934 * list of catalog entries.
935 *
936 * Implements (or tries to) 7.1. External Identifier Resolution
937 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
938 *
939 * Returns the URI of the resource or NULL if not found
940 */
941static xmlChar *
942xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
943 const xmlChar *sysID) {
944 xmlChar *ret = NULL;
945 xmlCatalogEntryPtr cur;
946 int haveDelegate = 0;
947 int haveNext = 0;
948
949 /*
950 * First tries steps 2/ 3/ 4/ if a system ID is provided.
951 */
952 if (sysID != NULL) {
953 xmlCatalogEntryPtr rewrite = NULL;
954 int lenrewrite = 0, len;
955 cur = catal;
956 haveDelegate = 0;
957 while (cur != NULL) {
958 switch (cur->type) {
959 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000960 if (xmlStrEqual(sysID, cur->name)) {
961 if (xmlDebugCatalogs)
962 xmlGenericError(xmlGenericErrorContext,
963 "Found system match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +0000964 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000965 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000966 break;
967 case XML_CATA_REWRITE_SYSTEM:
968 len = xmlStrlen(cur->name);
969 if ((len > lenrewrite) &&
970 (!xmlStrncmp(sysID, cur->name, len))) {
971 lenrewrite = len;
972 rewrite = cur;
973 }
974 break;
975 case XML_CATA_DELEGATE_SYSTEM:
976 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
977 haveDelegate++;
978 break;
979 case XML_CATA_NEXT_CATALOG:
980 haveNext++;
981 break;
982 default:
983 break;
984 }
985 cur = cur->next;
986 }
987 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000988 if (xmlDebugCatalogs)
989 xmlGenericError(xmlGenericErrorContext,
990 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardcda96922001-08-21 10:56:31 +0000991 ret = xmlStrdup(rewrite->value);
992 if (ret != NULL)
993 ret = xmlStrcat(ret, &sysID[lenrewrite]);
994 return(ret);
995 }
996 if (haveDelegate) {
997 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000998 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +0000999 * matches when the list was produced.
1000 */
1001 cur = catal;
1002 while (cur != NULL) {
1003 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1004 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
1005 if (cur->children == NULL) {
1006 xmlFetchXMLCatalogFile(cur);
1007 }
1008 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001009 if (xmlDebugCatalogs)
1010 xmlGenericError(xmlGenericErrorContext,
1011 "Trying system delegate %s\n", cur->value);
1012 ret = xmlCatalogListXMLResolve(cur->children, NULL,
1013 sysID);
1014 if (ret != NULL)
1015 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001016 }
1017 }
1018 cur = cur->next;
1019 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001020 /*
1021 * Apply the cut algorithm explained in 4/
1022 */
1023 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001024 }
1025 }
1026 /*
1027 * Then tries 5/ 6/ if a public ID is provided
1028 */
1029 if (pubID != NULL) {
1030 cur = catal;
1031 haveDelegate = 0;
1032 while (cur != NULL) {
1033 switch (cur->type) {
1034 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001035 if (xmlStrEqual(pubID, cur->name)) {
1036 if (xmlDebugCatalogs)
1037 xmlGenericError(xmlGenericErrorContext,
1038 "Found public match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001039 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001040 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001041 break;
1042 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001043 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1044 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001045 haveDelegate++;
1046 break;
1047 case XML_CATA_NEXT_CATALOG:
1048 if (sysID == NULL)
1049 haveNext++;
1050 break;
1051 default:
1052 break;
1053 }
1054 cur = cur->next;
1055 }
1056 if (haveDelegate) {
1057 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001058 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001059 * matches when the list was produced.
1060 */
1061 cur = catal;
1062 while (cur != NULL) {
1063 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001064 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1065 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001066 if (cur->children == NULL) {
1067 xmlFetchXMLCatalogFile(cur);
1068 }
1069 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001070 if (xmlDebugCatalogs)
1071 xmlGenericError(xmlGenericErrorContext,
1072 "Trying public delegate %s\n", cur->value);
1073 ret = xmlCatalogListXMLResolve(cur->children, pubID,
1074 NULL);
1075 if (ret != NULL)
1076 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001077 }
1078 }
1079 cur = cur->next;
1080 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001081 /*
1082 * Apply the cut algorithm explained in 4/
1083 */
1084 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001085 }
1086 }
1087 if (haveNext) {
1088 cur = catal;
1089 while (cur != NULL) {
1090 if (cur->type == XML_CATA_NEXT_CATALOG) {
1091 if (cur->children == NULL) {
1092 xmlFetchXMLCatalogFile(cur);
1093 }
1094 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001095 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1096 if (ret != NULL)
1097 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001098 }
1099 }
1100 cur = cur->next;
1101 }
1102 }
1103
1104 return(NULL);
1105}
1106
1107/**
1108 * xmlCatalogListXMLResolve:
1109 * @catal: a catalog list
1110 * @pubId: the public ID string
1111 * @sysId: the system ID string
1112 *
1113 * Do a complete resolution lookup of an External Identifier for a
1114 * list of catalogs
1115 *
1116 * Implements (or tries to) 7.1. External Identifier Resolution
1117 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1118 *
1119 * Returns the URI of the resource or NULL if not found
1120 */
1121static xmlChar *
1122xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1123 const xmlChar *sysID) {
1124 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001125 xmlChar *urnID = NULL;
1126
1127 if (catal == NULL)
1128 return(NULL);
1129 if ((pubID == NULL) && (sysID == NULL))
1130 return(NULL);
1131
1132 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1133 urnID = xmlCatalogUnWrapURN(pubID);
1134 if (xmlDebugCatalogs) {
1135 if (urnID == NULL)
1136 xmlGenericError(xmlGenericErrorContext,
1137 "Public URN ID %s expanded to NULL\n", pubID);
1138 else
1139 xmlGenericError(xmlGenericErrorContext,
1140 "Public URN ID expanded to %s\n", urnID);
1141 }
1142 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1143 if (urnID != NULL)
1144 xmlFree(urnID);
1145 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001146 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001147 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1148 urnID = xmlCatalogUnWrapURN(sysID);
1149 if (xmlDebugCatalogs) {
1150 if (urnID == NULL)
1151 xmlGenericError(xmlGenericErrorContext,
1152 "System URN ID %s expanded to NULL\n", sysID);
1153 else
1154 xmlGenericError(xmlGenericErrorContext,
1155 "System URN ID expanded to %s\n", urnID);
1156 }
1157 if (pubID == NULL)
1158 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1159 else if (xmlStrEqual(pubID, urnID))
1160 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1161 else {
1162 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1163 }
1164 if (urnID != NULL)
1165 xmlFree(urnID);
1166 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001167 }
1168 while (catal != NULL) {
1169 if (catal->type == XML_CATA_CATALOG) {
1170 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001171 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001172 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001173 if (catal->children != NULL) {
1174 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1175 if (ret != NULL)
1176 return(ret);
1177 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001178 }
1179 catal = catal->next;
1180 }
1181 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001182}
1183
1184/************************************************************************
1185 * *
1186 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001187 * *
1188 ************************************************************************/
1189
1190
1191#define RAW *cur
1192#define NEXT cur++;
1193#define SKIP(x) cur += x;
1194
1195#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1196
1197static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001198xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001199 if ((cur[0] != '-') || (cur[1] != '-'))
1200 return(cur);
1201 SKIP(2);
1202 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1203 NEXT;
1204 if (cur[0] == 0) {
1205 return(NULL);
1206 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001207 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001208}
1209
1210static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001211xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001212 xmlChar *buf = NULL;
1213 int len = 0;
1214 int size = 50;
1215 xmlChar stop;
1216 int count = 0;
1217
1218 *id = NULL;
1219
1220 if (RAW == '"') {
1221 NEXT;
1222 stop = '"';
1223 } else if (RAW == '\'') {
1224 NEXT;
1225 stop = '\'';
1226 } else {
1227 stop = ' ';
1228 }
1229 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1230 if (buf == NULL) {
1231 xmlGenericError(xmlGenericErrorContext,
1232 "malloc of %d byte failed\n", size);
1233 return(NULL);
1234 }
1235 while (xmlIsPubidChar(*cur)) {
1236 if ((*cur == stop) && (stop != ' '))
1237 break;
1238 if ((stop == ' ') && (IS_BLANK(*cur)))
1239 break;
1240 if (len + 1 >= size) {
1241 size *= 2;
1242 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1243 if (buf == NULL) {
1244 xmlGenericError(xmlGenericErrorContext,
1245 "realloc of %d byte failed\n", size);
1246 return(NULL);
1247 }
1248 }
1249 buf[len++] = *cur;
1250 count++;
1251 NEXT;
1252 }
1253 buf[len] = 0;
1254 if (stop == ' ') {
1255 if (!IS_BLANK(*cur)) {
1256 xmlFree(buf);
1257 return(NULL);
1258 }
1259 } else {
1260 if (*cur != stop) {
1261 xmlFree(buf);
1262 return(NULL);
1263 }
1264 NEXT;
1265 }
1266 *id = buf;
1267 return(cur);
1268}
1269
1270static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001271xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001272 xmlChar buf[XML_MAX_NAMELEN + 5];
1273 int len = 0;
1274 int c;
1275
1276 *name = NULL;
1277
1278 /*
1279 * Handler for more complex cases
1280 */
1281 c = *cur;
1282 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
1283 return(NULL);
1284 }
1285
1286 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
1287 (c == '.') || (c == '-') ||
1288 (c == '_') || (c == ':'))) {
1289 buf[len++] = c;
1290 cur++;
1291 c = *cur;
1292 if (len >= XML_MAX_NAMELEN)
1293 return(NULL);
1294 }
1295 *name = xmlStrndup(buf, len);
1296 return(cur);
1297}
1298
Daniel Veillard344cee72001-08-20 00:08:40 +00001299static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00001300xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001301 xmlCatalogEntryType type = XML_CATA_NONE;
1302 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
1303 type = SGML_CATA_SYSTEM;
1304 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
1305 type = SGML_CATA_PUBLIC;
1306 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1307 type = SGML_CATA_DELEGATE;
1308 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
1309 type = SGML_CATA_ENTITY;
1310 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
1311 type = SGML_CATA_DOCTYPE;
1312 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
1313 type = SGML_CATA_LINKTYPE;
1314 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
1315 type = SGML_CATA_NOTATION;
1316 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
1317 type = SGML_CATA_SGMLDECL;
1318 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
1319 type = SGML_CATA_DOCUMENT;
1320 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
1321 type = SGML_CATA_CATALOG;
1322 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
1323 type = SGML_CATA_BASE;
1324 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1325 type = SGML_CATA_DELEGATE;
1326 return(type);
1327}
1328
Daniel Veillarda7374592001-05-10 14:17:55 +00001329static int
Daniel Veillardcda96922001-08-21 10:56:31 +00001330xmlParseSGMLCatalog(const xmlChar *value, const char *file) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001331 const xmlChar *cur = value;
1332 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001333 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00001334
1335 if ((cur == NULL) || (file == NULL))
1336 return(-1);
1337 base = xmlStrdup((const xmlChar *) file);
1338
1339 while ((cur != NULL) && (cur[0] != '0')) {
1340 SKIP_BLANKS;
1341 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001342 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00001343 if (cur == NULL) {
1344 /* error */
1345 break;
1346 }
1347 } else {
1348 xmlChar *sysid = NULL;
1349 xmlChar *name = NULL;
1350 xmlCatalogEntryType type = XML_CATA_NONE;
1351
Daniel Veillardcda96922001-08-21 10:56:31 +00001352 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001353 if (name == NULL) {
1354 /* error */
1355 break;
1356 }
1357 if (!IS_BLANK(*cur)) {
1358 /* error */
1359 break;
1360 }
1361 SKIP_BLANKS;
1362 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001363 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00001364 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001365 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00001366 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001367 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001368 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001369 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00001370 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001371 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001372 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001373 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001374 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001375 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00001376 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001377 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001378 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001379 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00001380 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001381 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00001382 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001383 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001384 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001385 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001386 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
1387 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001388 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001389 if (name == NULL) {
1390 /* error */
1391 break;
1392 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001393 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001394 continue;
1395 }
1396 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001397 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001398
1399 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001400 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00001401 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00001402 type = SGML_CATA_PENTITY;
1403 case SGML_CATA_PENTITY:
1404 case SGML_CATA_DOCTYPE:
1405 case SGML_CATA_LINKTYPE:
1406 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00001407 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001408 if (cur == NULL) {
1409 /* error */
1410 break;
1411 }
1412 if (!IS_BLANK(*cur)) {
1413 /* error */
1414 break;
1415 }
1416 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001417 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001418 if (cur == NULL) {
1419 /* error */
1420 break;
1421 }
1422 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001423 case SGML_CATA_PUBLIC:
1424 case SGML_CATA_SYSTEM:
1425 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00001426 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001427 if (cur == NULL) {
1428 /* error */
1429 break;
1430 }
1431 if (!IS_BLANK(*cur)) {
1432 /* error */
1433 break;
1434 }
1435 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001436 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001437 if (cur == NULL) {
1438 /* error */
1439 break;
1440 }
1441 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001442 case SGML_CATA_BASE:
1443 case SGML_CATA_CATALOG:
1444 case SGML_CATA_DOCUMENT:
1445 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00001446 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001447 if (cur == NULL) {
1448 /* error */
1449 break;
1450 }
1451 break;
1452 default:
1453 break;
1454 }
1455 if (cur == NULL) {
1456 if (name != NULL)
1457 xmlFree(name);
1458 if (sysid != NULL)
1459 xmlFree(sysid);
1460 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001461 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001462 if (base != NULL)
1463 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001464 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00001465 } else if ((type == SGML_CATA_PUBLIC) ||
1466 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001467 xmlChar *filename;
1468
1469 filename = xmlBuildURI(sysid, base);
1470 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001471 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00001472
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001473 entry = xmlNewCatalogEntry(type, name, filename,
1474 XML_CATA_PREFER_NONE);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001475 res = xmlHashAddEntry(xmlDefaultCatalog, name, entry);
1476 if (res < 0) {
1477 xmlFreeCatalogEntry(entry);
1478 }
1479 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00001480 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001481
Daniel Veillard344cee72001-08-20 00:08:40 +00001482 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001483 xmlChar *filename;
1484
1485 filename = xmlBuildURI(sysid, base);
1486 if (filename != NULL) {
1487 xmlLoadCatalog((const char *)filename);
1488 xmlFree(filename);
1489 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001490 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001491 /*
1492 * drop anything else we won't handle it
1493 */
1494 if (name != NULL)
1495 xmlFree(name);
1496 if (sysid != NULL)
1497 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001498 }
1499 }
1500 if (base != NULL)
1501 xmlFree(base);
1502 if (cur == NULL)
1503 return(-1);
1504 return(0);
1505}
1506
Daniel Veillardcda96922001-08-21 10:56:31 +00001507/**
1508 * xmlCatalogGetSGMLPublic:
1509 * @catal: an SGML catalog hash
1510 * @pubId: the public ID string
1511 *
1512 * Try to lookup the system ID associated to a public ID
1513 *
1514 * Returns the system ID if found or NULL otherwise.
1515 */
1516static const xmlChar *
1517xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
1518 xmlCatalogEntryPtr entry;
1519
1520 if (catal == NULL)
1521 return(NULL);
1522
1523 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
1524 if (entry == NULL)
1525 return(NULL);
1526 if (entry->type == SGML_CATA_PUBLIC)
1527 return(entry->value);
1528 return(NULL);
1529}
1530
1531/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001532 * xmlCatalogGetSGMLSystem:
1533 * @catal: an SGML catalog hash
1534 * @sysId: the public ID string
1535 *
1536 * Try to lookup the catalog local reference for a system ID
1537 *
1538 * Returns the system ID if found or NULL otherwise.
1539 */
1540static const xmlChar *
1541xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
1542 xmlCatalogEntryPtr entry;
1543
1544 if (catal == NULL)
1545 return(NULL);
1546
1547 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
1548 if (entry == NULL)
1549 return(NULL);
1550 if (entry->type == SGML_CATA_SYSTEM)
1551 return(entry->value);
1552 return(NULL);
1553}
1554
1555/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001556 * xmlCatalogSGMLResolve:
1557 * @pubId: the public ID string
1558 * @sysId: the system ID string
1559 *
1560 * Do a complete resolution lookup of an External Identifier
1561 *
1562 * Returns the URI of the resource or NULL if not found
1563 */
1564static const xmlChar *
1565xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00001566 const xmlChar *ret = NULL;
1567
1568 if (xmlDefaultCatalog == NULL)
1569 return(NULL);
1570
1571 if (pubID != NULL)
1572 ret = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
1573 if (ret != NULL)
1574 return(ret);
1575 if (sysID != NULL)
1576 ret = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00001577 return(NULL);
1578}
1579
Daniel Veillarda7374592001-05-10 14:17:55 +00001580/************************************************************************
1581 * *
1582 * Public interfaces *
1583 * *
1584 ************************************************************************/
1585
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001586/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001587 * xmlInitializeCatalog:
1588 *
1589 * Do the catalog initialization.
1590 * TODO: this function is not thread safe, catalog initialization should
1591 * preferably be done once at startup
1592 */
1593void
1594xmlInitializeCatalog(void) {
1595 const char *catalogs;
1596
1597 if (xmlCatalogInitialized != 0)
1598 return;
1599
1600 if (getenv("XML_DEBUG_CATALOG"))
1601 xmlDebugCatalogs = 1;
1602 if ((xmlDefaultXMLCatalogList == NULL) && (xmlDefaultCatalog == NULL)) {
1603 catalogs = getenv("XML_CATALOG_FILES");
1604 if (catalogs == NULL)
1605 catalogs = XML_DEFAULT_CATALOG;
1606 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
1607 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
1608 }
1609
1610 xmlCatalogInitialized = 1;
1611}
1612
1613/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001614 * xmlLoadCatalog:
1615 * @filename: a file path
1616 *
Daniel Veillard81418e32001-05-22 15:08:55 +00001617 * Load the catalog and makes its definitions effective for the default
1618 * external entity loader. It will recuse in CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001619 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001620 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00001621 *
1622 * Returns 0 in case of success -1 in case of error
1623 */
1624int
1625xmlLoadCatalog(const char *filename) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001626 int fd, len, ret, i;
Daniel Veillarda7374592001-05-10 14:17:55 +00001627 struct stat info;
1628 xmlChar *content;
1629
1630 if (filename == NULL)
1631 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001632
Daniel Veillarda7374592001-05-10 14:17:55 +00001633 if (xmlDefaultCatalog == NULL)
1634 xmlDefaultCatalog = xmlHashCreate(20);
1635 if (xmlDefaultCatalog == NULL)
1636 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001637
1638 /*
1639 * Need to be done after ...
1640 */
1641 if (!xmlCatalogInitialized)
1642 xmlInitializeCatalog();
1643
1644#ifdef HAVE_STAT
Daniel Veillarda7374592001-05-10 14:17:55 +00001645 if (stat(filename, &info) < 0)
1646 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001647#endif
Daniel Veillarda7374592001-05-10 14:17:55 +00001648
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001649 /*
1650 * Prevent loops
1651 */
1652 for (i = 0;i < catalNr;i++) {
Daniel Veillard81418e32001-05-22 15:08:55 +00001653 if (xmlStrEqual((const xmlChar *)catalTab[i],
1654 (const xmlChar *)filename)) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001655 xmlGenericError(xmlGenericErrorContext,
1656 "xmlLoadCatalog: %s seems to induce a loop\n",
1657 filename);
1658 return(-1);
1659 }
1660 }
1661 if (catalNr >= catalMax) {
1662 xmlGenericError(xmlGenericErrorContext,
1663 "xmlLoadCatalog: %s catalog list too deep\n",
1664 filename);
1665 return(-1);
1666 }
1667 catalTab[catalNr++] = filename;
1668
1669 if ((fd = open(filename, O_RDONLY)) < 0) {
1670 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001671 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001672 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001673
1674 content = xmlMalloc(info.st_size + 10);
1675 if (content == NULL) {
1676 xmlGenericError(xmlGenericErrorContext,
1677 "realloc of %d byte failed\n", info.st_size + 10);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001678 catalNr--;
1679 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00001680 }
1681 len = read(fd, content, info.st_size);
1682 if (len < 0) {
1683 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001684 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001685 return(-1);
1686 }
1687 content[len] = 0;
1688 close(fd);
1689
Daniel Veillard344cee72001-08-20 00:08:40 +00001690 if ((content[0] == ' ') || (content[0] == '-') ||
1691 ((content[0] >= 'A') && (content[0] <= 'Z')) ||
1692 ((content[0] >= 'a') && (content[0] <= 'z')))
Daniel Veillardcda96922001-08-21 10:56:31 +00001693 ret = xmlParseSGMLCatalog(content, filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001694 else {
1695 xmlCatalogEntryPtr catal, tmp;
1696 /* TODO: allow to switch the default preference */
1697 catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
1698 if (catal != NULL) {
1699 if (xmlDefaultXMLCatalogList == NULL)
1700 xmlDefaultXMLCatalogList = catal;
1701 else {
1702 tmp = xmlDefaultXMLCatalogList;
1703 while (tmp->next != NULL)
1704 tmp = tmp->next;
1705 tmp->next = catal;
1706 }
1707 ret = 0;
1708 } else
1709 ret = -1;
1710 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001711 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001712 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001713 return(ret);
1714}
1715
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001716/**
Daniel Veillard81418e32001-05-22 15:08:55 +00001717 * xmlLoadCatalogs:
1718 * @paths: a list of file path separated by ':' or spaces
1719 *
1720 * Load the catalogs and makes their definitions effective for the default
1721 * external entity loader.
1722 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001723 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00001724 */
1725void
1726xmlLoadCatalogs(const char *pathss) {
1727 const char *cur;
1728 const char *paths;
1729 xmlChar *path;
1730
1731 cur = pathss;
1732 while ((cur != NULL) && (*cur != 0)) {
1733 while (IS_BLANK(*cur)) cur++;
1734 if (*cur != 0) {
1735 paths = cur;
1736 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
1737 cur++;
1738 path = xmlStrndup((const xmlChar *)paths, cur - paths);
1739 if (path != NULL) {
1740 xmlLoadCatalog((const char *) path);
1741 xmlFree(path);
1742 }
1743 }
1744 while (*cur == ':')
1745 cur++;
1746 }
1747}
1748
Daniel Veillarda7374592001-05-10 14:17:55 +00001749/**
1750 * xmlCatalogCleanup:
1751 *
1752 * Free up all the memory associated with catalogs
1753 */
1754void
1755xmlCatalogCleanup(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001756 if (xmlDebugCatalogs)
1757 xmlGenericError(xmlGenericErrorContext,
1758 "Catalogs cleanup\n");
Daniel Veillardcda96922001-08-21 10:56:31 +00001759 if (xmlDefaultXMLCatalogList != NULL)
1760 xmlFreeCatalogEntryList(xmlDefaultXMLCatalogList);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001761 xmlDefaultXMLCatalogList = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001762 if (xmlDefaultCatalog != NULL)
1763 xmlHashFree(xmlDefaultCatalog,
1764 (xmlHashDeallocator) xmlFreeCatalogEntry);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001765 xmlDebugCatalogs = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00001766 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001767 xmlCatalogInitialized = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00001768}
1769
1770/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001771 * xmlCatalogGetSystem:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001772 * @pubId: the public ID string
Daniel Veillarda7374592001-05-10 14:17:55 +00001773 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001774 * Try to lookup the system ID associated to a public ID
1775 * DEPRECATED, use xmlCatalogResolveSystem()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001776 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001777 * Returns the system ID if found or NULL otherwise.
Daniel Veillarda7374592001-05-10 14:17:55 +00001778 */
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001779const xmlChar *
1780xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001781 xmlChar *ret;
1782 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001783
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001784 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001785 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001786
1787 if (!xmlCatalogInitialized)
1788 xmlInitializeCatalog();
1789
1790 /*
1791 * Check first the XML catalogs
1792 */
1793 if (xmlDefaultXMLCatalogList != NULL) {
1794 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
1795 if (ret != NULL) {
1796 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
1797 result[sizeof(result) - 1] = 0;
1798 return(result);
1799 }
1800 }
1801
1802 if (xmlDefaultCatalog != NULL)
1803 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID));
1804 return(NULL);
1805}
1806
1807/**
1808 * xmlCatalogResolveSystem:
1809 * @sysId: the public ID string
1810 *
1811 * Try to lookup the catalog resource for a system ID
1812 *
1813 * Returns the system ID if found or NULL otherwise, the value returned
1814 * must be freed by the caller.
1815 */
1816xmlChar *
1817xmlCatalogResolveSystem(const xmlChar *sysID) {
1818 xmlCatalogEntryPtr catal;
1819 xmlChar *ret;
1820 const xmlChar *sgml;
1821
1822 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001823 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001824
1825 if (!xmlCatalogInitialized)
1826 xmlInitializeCatalog();
1827
1828 /*
1829 * Check first the XML catalogs
1830 */
1831 catal = xmlDefaultXMLCatalogList;
1832 if (catal != NULL) {
1833 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
1834 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
1835 return(ret);
1836 }
1837
1838 if (xmlDefaultCatalog != NULL) {
1839 sgml = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
1840 if (sgml != NULL)
1841 return(xmlStrdup(sgml));
1842 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001843 return(NULL);
1844}
1845
1846/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001847 * xmlCatalogGetPublic:
1848 * @pubId: the public ID string
1849 *
1850 * Try to lookup the system ID associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001851 * DEPRECATED, use xmlCatalogResolvePublic()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001852 *
1853 * Returns the system ID if found or NULL otherwise.
1854 */
1855const xmlChar *
1856xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001857 xmlChar *ret;
1858 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001859
Daniel Veillard344cee72001-08-20 00:08:40 +00001860 if (pubID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001861 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001862
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001863 if (!xmlCatalogInitialized)
1864 xmlInitializeCatalog();
1865
1866 /*
1867 * Check first the XML catalogs
1868 */
1869 if (xmlDefaultXMLCatalogList != NULL) {
1870 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
1871 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
1872 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
1873 result[sizeof(result) - 1] = 0;
1874 return(result);
1875 }
1876 }
1877
1878 if (xmlDefaultCatalog != NULL)
1879 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
1880 return(NULL);
1881}
1882
1883/**
1884 * xmlCatalogResolvePublic:
1885 * @pubId: the public ID string
1886 *
1887 * Try to lookup the system ID associated to a public ID
1888 *
1889 * Returns the system ID if found or NULL otherwise, the value returned
1890 * must be freed by the caller.
1891 */
1892xmlChar *
1893xmlCatalogResolvePublic(const xmlChar *pubID) {
1894 xmlCatalogEntryPtr catal;
1895 xmlChar *ret;
1896 const xmlChar *sgml;
1897
1898 if (pubID == NULL)
1899 return(NULL);
1900
1901 if (!xmlCatalogInitialized)
1902 xmlInitializeCatalog();
1903
Daniel Veillard344cee72001-08-20 00:08:40 +00001904 /*
1905 * Check first the XML catalogs
1906 */
1907 catal = xmlDefaultXMLCatalogList;
1908 if (catal != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001909 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
1910 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
Daniel Veillard344cee72001-08-20 00:08:40 +00001911 return(ret);
1912 }
1913
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001914 if (xmlDefaultCatalog != NULL) {
1915 sgml = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
1916 if (sgml != NULL)
1917 return(xmlStrdup(sgml));
1918 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001919 return(NULL);
1920}
Daniel Veillard344cee72001-08-20 00:08:40 +00001921
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001922/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001923 * xmlCatalogResolve:
1924 * @pubId: the public ID string
1925 * @sysId: the system ID string
1926 *
1927 * Do a complete resolution lookup of an External Identifier
1928 *
1929 * Returns the URI of the resource or NULL if not found, it must be freed
1930 * by the caller.
1931 */
1932xmlChar *
1933xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001934 if (!xmlCatalogInitialized)
1935 xmlInitializeCatalog();
1936
Daniel Veillardcda96922001-08-21 10:56:31 +00001937 if (xmlDefaultXMLCatalogList != NULL) {
1938 return(xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, sysID));
1939 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001940 const xmlChar *ret;
1941
1942 ret = xmlCatalogSGMLResolve(pubID, sysID);
1943 if (ret != NULL)
1944 return(xmlStrdup(ret));
Daniel Veillardcda96922001-08-21 10:56:31 +00001945 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001946 return(NULL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001947}
1948
1949/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001950 * xmlCatalogDump:
1951 * @out: the file.
1952 *
1953 * Free up all the memory associated with catalogs
1954 */
1955void
1956xmlCatalogDump(FILE *out) {
1957 if (out == NULL)
1958 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00001959
1960 if (xmlDefaultXMLCatalogList != NULL) {
1961 xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList);
1962 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001963 xmlHashScan(xmlDefaultCatalog,
1964 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00001965 }
1966}
1967
1968/**
1969 * xmlCatalogAdd:
1970 * @type: the type of record to add to the catalog
1971 * @orig: the system, public or prefix to match
1972 * @replace: the replacement value for the match
1973 *
1974 * Add an entry in the catalog, it may overwrite existing but
1975 * different entries.
1976 *
1977 * Returns 0 if successful, -1 otherwise
1978 */
1979int
1980xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
1981 int res = -1;
1982
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001983 if (!xmlCatalogInitialized)
1984 xmlInitializeCatalog();
1985
Daniel Veillard344cee72001-08-20 00:08:40 +00001986 if (xmlDefaultXMLCatalogList != NULL) {
1987 res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
1988 } else if (xmlDefaultCatalog != NULL) {
1989 xmlCatalogEntryType typ;
1990
Daniel Veillardcda96922001-08-21 10:56:31 +00001991 typ = xmlGetSGMLCatalogEntryType(type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001992 if (type != XML_CATA_NONE) {
1993 xmlCatalogEntryPtr entry;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001994 entry = xmlNewCatalogEntry(typ, orig, replace, XML_CATA_PREFER_NONE);
Daniel Veillard344cee72001-08-20 00:08:40 +00001995 res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
1996 }
1997 }
1998 return(res);
1999}
2000
2001/**
2002 * xmlCatalogRemove:
2003 * @value: the value to remove
2004 *
2005 * Remove an entry from the catalog
2006 *
2007 * Returns 0 if successful, -1 otherwise
2008 */
2009int
2010xmlCatalogRemove(const xmlChar *value) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002011 int res = -1;
2012
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002013 if (!xmlCatalogInitialized)
2014 xmlInitializeCatalog();
2015
Daniel Veillardcda96922001-08-21 10:56:31 +00002016 if (xmlDefaultXMLCatalogList != NULL) {
2017 res = xmlDelXMLCatalog(xmlDefaultXMLCatalogList, value);
2018 } else if (xmlDefaultCatalog != NULL) {
2019 TODO
2020 }
2021 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00002022}
2023
2024/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002025 * xmlCatalogGetDefaults:
2026 *
2027 * Used to get the user preference w.r.t. to what catalogs should
2028 * be accepted
2029 *
2030 * Returns the current xmlCatalogAllow value
2031 */
2032xmlCatalogAllow
2033xmlCatalogGetDefaults(void) {
2034 return(xmlCatalogDefaultAllow);
2035}
2036
2037/**
2038 * xmlCatalogSetDefaults:
2039 *
2040 * Used to set the user preference w.r.t. to what catalogs should
2041 * be accepted
2042 */
2043void
2044xmlCatalogSetDefaults(xmlCatalogAllow allow) {
2045 if (!xmlCatalogInitialized)
2046 xmlInitializeCatalog();
2047 if (xmlDebugCatalogs) {
2048 switch (allow) {
2049 case XML_CATA_ALLOW_NONE:
2050 xmlGenericError(xmlGenericErrorContext,
2051 "Disabling catalog usage\n");
2052 break;
2053 case XML_CATA_ALLOW_GLOBAL:
2054 xmlGenericError(xmlGenericErrorContext,
2055 "Allowing only global catalogs\n");
2056 break;
2057 case XML_CATA_ALLOW_DOCUMENT:
2058 xmlGenericError(xmlGenericErrorContext,
2059 "Allowing only catalogs from the document\n");
2060 break;
2061 case XML_CATA_ALLOW_ALL:
2062 xmlGenericError(xmlGenericErrorContext,
2063 "Allowing all catalogs\n");
2064 break;
2065 }
2066 }
2067 xmlCatalogDefaultAllow = allow;
2068}
2069
2070/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002071 * xmlCatalogSetDefaultPrefer:
2072 * @prefer: the default preference for delegation
2073 *
2074 * Allows to set the preference between public and system for deletion
2075 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002076 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002077 *
2078 * Returns the previous value of the default preference for delegation
2079 */
2080xmlCatalogPrefer
2081xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
2082 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
2083
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002084 if (!xmlCatalogInitialized)
2085 xmlInitializeCatalog();
2086 if (prefer == XML_CATA_PREFER_NONE)
2087 return(ret);
2088
2089 if (xmlDebugCatalogs) {
2090 switch (prefer) {
2091 case XML_CATA_PREFER_PUBLIC:
2092 xmlGenericError(xmlGenericErrorContext,
2093 "Setting catalog preference to PUBLIC\n");
2094 break;
2095 case XML_CATA_PREFER_SYSTEM:
2096 xmlGenericError(xmlGenericErrorContext,
2097 "Setting catalog preference to SYSTEM\n");
2098 break;
2099 case XML_CATA_PREFER_NONE:
2100 break;
2101 }
2102 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002103 xmlCatalogDefaultPrefer = prefer;
2104 return(ret);
2105}
2106
2107/**
Daniel Veillard344cee72001-08-20 00:08:40 +00002108 * xmlCatalogSetDebug:
2109 * @level: the debug level of catalogs required
2110 *
2111 * Used to set the debug level for catalog operation, 0 disable
2112 * debugging, 1 enable it
2113 *
2114 * Returns the previous value of the catalog debugging level
2115 */
2116int
2117xmlCatalogSetDebug(int level) {
2118 int ret = xmlDebugCatalogs;
2119
2120 if (level <= 0)
2121 xmlDebugCatalogs = 0;
2122 else
2123 xmlDebugCatalogs = level;
2124 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002125}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002126
2127/**
2128 * xmlCatalogFreeLocal:
2129 * @catalogs: a document's list of catalogs
2130 *
2131 * Free up the memory associated to the catalog list
2132 */
2133void
2134xmlCatalogFreeLocal(void *catalogs) {
2135 xmlCatalogEntryPtr catal;
2136
2137 catal = (xmlCatalogEntryPtr) catalogs;
2138 if (catal != NULL)
2139 xmlFreeCatalogEntryList(catal);
2140}
2141
2142
2143/**
2144 * xmlCatalogAddLocal:
2145 * @catalogs: a document's list of catalogs
2146 * @URL: the URL to a new local catalog
2147 *
2148 * Add the new entry to the catalog list
2149 *
2150 * Returns the updated list
2151 */
2152void *
2153xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
2154 xmlCatalogEntryPtr catal, add;
2155
2156 if (!xmlCatalogInitialized)
2157 xmlInitializeCatalog();
2158 if (URL == NULL)
2159 return(catalogs);
2160
2161 if (xmlDebugCatalogs)
2162 xmlGenericError(xmlGenericErrorContext,
2163 "Adding document catalog %s\n", URL);
2164
2165 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
2166 xmlCatalogDefaultPrefer);
2167 if (add == NULL)
2168 return(catalogs);
2169
2170 catal = (xmlCatalogEntryPtr) catalogs;
2171 if (catal == NULL)
2172 return((void *) add);
2173
2174 while (catal->next != NULL)
2175 catal = catal->next;
2176 catal->next = add;
2177 return(catalogs);
2178}
2179
2180/**
2181 * xmlCatalogLocalResolve:
2182 * @catalogs: a document's list of catalogs
2183 * @pubId: the public ID string
2184 * @sysId: the system ID string
2185 *
2186 * Do a complete resolution lookup of an External Identifier using a
2187 * document's private catalog list
2188 *
2189 * Returns the URI of the resource or NULL if not found, it must be freed
2190 * by the caller.
2191 */
2192xmlChar *
2193xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
2194 const xmlChar *sysID) {
2195 xmlCatalogEntryPtr catal;
2196
2197 if (!xmlCatalogInitialized)
2198 xmlInitializeCatalog();
2199 catal = (xmlCatalogEntryPtr) catalogs;
2200 if (catal == NULL)
2201 return(NULL);
2202 return(xmlCatalogListXMLResolve(catal, pubID, sysID));
2203}
2204
Daniel Veillarda7374592001-05-10 14:17:55 +00002205#endif /* LIBXML_CATALOG_ENABLED */