blob: 3ec98f8a7c6cbbd70088e15de3d106df628c8849 [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);
Daniel Veillard344cee72001-08-20 00:08:40 +0000322static xmlCatalogEntryPtr
323xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
324 const char *file);
325static void
326xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
327 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000328static xmlChar *
329xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
330 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000331static xmlChar *
332xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
333
Daniel Veillard344cee72001-08-20 00:08:40 +0000334
335static xmlCatalogEntryType
336xmlGetXMLCatalogEntryType(const xmlChar *name) {
337 xmlCatalogEntryType type = XML_CATA_NONE;
338 if (xmlStrEqual(name, (const xmlChar *) "system"))
339 type = XML_CATA_SYSTEM;
340 else if (xmlStrEqual(name, (const xmlChar *) "public"))
341 type = XML_CATA_PUBLIC;
342 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
343 type = XML_CATA_REWRITE_SYSTEM;
344 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
345 type = XML_CATA_DELEGATE_PUBLIC;
346 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
347 type = XML_CATA_DELEGATE_SYSTEM;
348 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
349 type = XML_CATA_URI;
350 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
351 type = XML_CATA_REWRITE_URI;
352 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
353 type = XML_CATA_DELEGATE_URI;
354 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
355 type = XML_CATA_NEXT_CATALOG;
356 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
357 type = XML_CATA_CATALOG;
358 return(type);
359}
360
361static xmlCatalogEntryPtr
362xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
363 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000364 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000365 int ok = 1;
366 xmlChar *uriValue;
367 xmlChar *nameValue = NULL;
368 xmlChar *base = NULL;
369 xmlChar *URL = NULL;
370 xmlCatalogEntryPtr ret = NULL;
371
372 if (attrName != NULL) {
373 nameValue = xmlGetProp(cur, attrName);
374 if (nameValue == NULL) {
375 xmlGenericError(xmlGenericErrorContext,
376 "%s entry lacks '%s'\n", name, attrName);
377 ok = 0;
378 }
379 }
380 uriValue = xmlGetProp(cur, uriAttrName);
381 if (uriValue == NULL) {
382 xmlGenericError(xmlGenericErrorContext,
383 "%s entry lacks '%s'\n", name, uriAttrName);
384 ok = 0;
385 }
386 if (!ok) {
387 if (nameValue != NULL)
388 xmlFree(nameValue);
389 if (uriValue != NULL)
390 xmlFree(uriValue);
391 return(NULL);
392 }
393
394 base = xmlNodeGetBase(cur->doc, cur);
395 URL = xmlBuildURI(uriValue, base);
396 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000397 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000398 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000399 xmlGenericError(xmlGenericErrorContext,
400 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000401 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000402 xmlGenericError(xmlGenericErrorContext,
403 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000404 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000405 ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000406 } else {
407 xmlGenericError(xmlGenericErrorContext,
408 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
409 }
410 if (nameValue != NULL)
411 xmlFree(nameValue);
412 if (uriValue != NULL)
413 xmlFree(uriValue);
414 if (base != NULL)
415 xmlFree(base);
416 if (URL != NULL)
417 xmlFree(URL);
418 return(ret);
419}
420
421static void
422xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
423 xmlCatalogEntryPtr parent)
424{
425 xmlChar *uri = NULL;
426 xmlChar *URL = NULL;
427 xmlChar *base = NULL;
428 xmlCatalogEntryPtr entry = NULL;
429
430 if (cur == NULL)
431 return;
432 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
433 xmlChar *prop;
434
435 prop = xmlGetProp(cur, BAD_CAST "prefer");
436 if (prop != NULL) {
437 if (xmlStrEqual(prop, BAD_CAST "system")) {
438 prefer = XML_CATA_PREFER_SYSTEM;
439 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
440 prefer = XML_CATA_PREFER_PUBLIC;
441 } else {
442 xmlGenericError(xmlGenericErrorContext,
443 "Invalid value for prefer: '%s'\n", prop);
444 }
445 xmlFree(prop);
446 }
447 /*
448 * Recurse to propagate prefer to the subtree
449 * (xml:base handling is automated)
450 */
451 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
452 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
453 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000454 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000455 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
456 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000457 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000458 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
459 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
460 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000461 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000462 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
463 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
464 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000465 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000466 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
467 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
468 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000469 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000470 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
471 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
472 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000473 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000474 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
475 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
476 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000477 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000478 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
479 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
480 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000481 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000482 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
483 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
484 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000485 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000486 }
487 if ((entry != NULL) && (parent != NULL)) {
488 entry->parent = parent;
489 if (parent->children == NULL)
490 parent->children = entry;
491 else {
492 xmlCatalogEntryPtr prev;
493
494 prev = parent->children;
495 while (prev->next != NULL)
496 prev = prev->next;
497 prev->next = entry;
498 }
499 }
500 if (base != NULL)
501 xmlFree(base);
502 if (uri != NULL)
503 xmlFree(uri);
504 if (URL != NULL)
505 xmlFree(URL);
506}
507
508static void
509xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
510 xmlCatalogEntryPtr parent) {
511 while (cur != NULL) {
512 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
513 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
514 xmlParseXMLCatalogNode(cur, prefer, parent);
515 }
516 cur = cur->next;
517 }
518 /* TODO: sort the list according to REWRITE lengths and prefer value */
519}
520
521static xmlCatalogEntryPtr
522xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
523 const char *file) {
524 xmlDocPtr doc;
525 xmlNodePtr cur;
526 xmlChar *prop;
527 xmlCatalogEntryPtr parent = NULL;
528
529 if ((value == NULL) || (file == NULL))
530 return(NULL);
531
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000532 if (xmlDebugCatalogs)
533 xmlGenericError(xmlGenericErrorContext,
534 "Parsing catalog %s's content\n", file);
535
Daniel Veillard344cee72001-08-20 00:08:40 +0000536 doc = xmlParseDoc((xmlChar *) value);
537 if (doc == NULL)
538 return(NULL);
539 doc->URL = xmlStrdup((const xmlChar *) file);
540
541 cur = xmlDocGetRootElement(doc);
542 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
543 (cur->ns != NULL) && (cur->ns->href != NULL) &&
544 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
545
Daniel Veillard344cee72001-08-20 00:08:40 +0000546 prop = xmlGetProp(cur, BAD_CAST "prefer");
547 if (prop != NULL) {
548 if (xmlStrEqual(prop, BAD_CAST "system")) {
549 prefer = XML_CATA_PREFER_SYSTEM;
550 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
551 prefer = XML_CATA_PREFER_PUBLIC;
552 } else {
553 xmlGenericError(xmlGenericErrorContext,
554 "Invalid value for prefer: '%s'\n",
555 prop);
556 }
557 xmlFree(prop);
558 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000559 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
560 (const xmlChar *)file, prefer);
561 if (parent == NULL) {
562 xmlFreeDoc(doc);
563 return(NULL);
564 }
565
Daniel Veillard344cee72001-08-20 00:08:40 +0000566 cur = cur->children;
567 xmlParseXMLCatalogNodeList(cur, prefer, parent);
568 } else {
569 xmlGenericError(xmlGenericErrorContext,
570 "File %s is not an XML Catalog\n", file);
571 xmlFreeDoc(doc);
572 return(NULL);
573 }
574 xmlFreeDoc(doc);
575 return(parent);
576}
577
578static xmlCatalogEntryPtr
579xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
580 xmlDocPtr doc;
581 xmlNodePtr cur;
582 xmlChar *prop;
583 xmlCatalogEntryPtr parent = NULL;
584
585 if (filename == NULL)
586 return(NULL);
587
588 doc = xmlParseFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000589 if (doc == NULL) {
590 if (xmlDebugCatalogs)
591 xmlGenericError(xmlGenericErrorContext,
592 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000593 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000594 }
595
596 if (xmlDebugCatalogs)
597 xmlGenericError(xmlGenericErrorContext,
598 "Parsing catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000599
600 cur = xmlDocGetRootElement(doc);
601 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
602 (cur->ns != NULL) && (cur->ns->href != NULL) &&
603 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
604
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000605 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
606 (const xmlChar *)filename, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000607 if (parent == NULL) {
608 xmlFreeDoc(doc);
609 return(NULL);
610 }
611
612 prop = xmlGetProp(cur, BAD_CAST "prefer");
613 if (prop != NULL) {
614 if (xmlStrEqual(prop, BAD_CAST "system")) {
615 prefer = XML_CATA_PREFER_SYSTEM;
616 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
617 prefer = XML_CATA_PREFER_PUBLIC;
618 } else {
619 xmlGenericError(xmlGenericErrorContext,
620 "Invalid value for prefer: '%s'\n",
621 prop);
622 }
623 xmlFree(prop);
624 }
625 cur = cur->children;
626 xmlParseXMLCatalogNodeList(cur, prefer, parent);
627 } else {
628 xmlGenericError(xmlGenericErrorContext,
629 "File %s is not an XML Catalog\n", filename);
630 xmlFreeDoc(doc);
631 return(NULL);
632 }
633 xmlFreeDoc(doc);
634 return(parent);
635}
636
Daniel Veillardcda96922001-08-21 10:56:31 +0000637/**
638 * xmlFetchXMLCatalogFile:
639 * @catal: an existing but incomplete catalog entry
640 *
641 * Fetch and parse the subcatalog referenced by an entry
642 * It tries to be thread safe but by lack of an atomic test and
643 * set there is a risk of loosing memory.
644 *
645 * Returns 0 in case of success, -1 otherwise
646 */
647static int
648xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
649 xmlCatalogEntryPtr children;
650
651 if (catal == NULL)
652 return(-1);
653 if (catal->value == NULL)
654 return(-1);
655 if (catal->children != NULL)
656 return(-1);
657
658 /*
659 * Fetch and parse
660 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000661 children = xmlParseXMLCatalogFile(catal->prefer, catal->value);
Daniel Veillardcda96922001-08-21 10:56:31 +0000662 if (children == NULL)
663 return(-1);
664
665 /*
666 * Where a real test and set would be needed !
667 */
668 if (catal->children == NULL) {
669 catal->children = children;
670 } else {
671 /*
672 * Another thread filled it before us
673 */
674 xmlFreeCatalogEntryList(children);
675 }
676 return(0);
677}
678
Daniel Veillard344cee72001-08-20 00:08:40 +0000679static int
680xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
681 int ret;
682 xmlDocPtr doc;
683 xmlNsPtr ns;
684 xmlDtdPtr dtd;
685 xmlNodePtr node, catalog;
686 xmlOutputBufferPtr buf;
687 xmlCatalogEntryPtr cur;
688
689 /*
690 * Rebuild a catalog
691 */
692 doc = xmlNewDoc(NULL);
693 if (doc == NULL)
694 return(-1);
695 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
696 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
697BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
698
699 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
700
701 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
702 if (ns == NULL) {
703 xmlFreeDoc(doc);
704 return(-1);
705 }
706 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
707 if (catalog == NULL) {
708 xmlFreeNs(ns);
709 xmlFreeDoc(doc);
710 return(-1);
711 }
712 catalog->nsDef = ns;
713 xmlAddChild((xmlNodePtr) doc, catalog);
714
715 /*
716 * add all the catalog entries
717 */
718 cur = catal;
719 while (cur != NULL) {
720 switch (cur->type) {
721 case XML_CATA_CATALOG:
722 if (cur == catal) {
723 cur = cur->children;
724 continue;
725 }
726 break;
727 case XML_CATA_NEXT_CATALOG:
728 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
729 xmlSetProp(node, BAD_CAST "catalog", cur->value);
730 xmlAddChild(catalog, node);
731 break;
732 case XML_CATA_NONE:
733 break;
734 case XML_CATA_PUBLIC:
735 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
736 xmlSetProp(node, BAD_CAST "publicId", cur->name);
737 xmlSetProp(node, BAD_CAST "uri", cur->value);
738 xmlAddChild(catalog, node);
739 break;
740 case XML_CATA_SYSTEM:
741 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
742 xmlSetProp(node, BAD_CAST "systemId", cur->name);
743 xmlSetProp(node, BAD_CAST "uri", cur->value);
744 xmlAddChild(catalog, node);
745 break;
746 case XML_CATA_REWRITE_SYSTEM:
747 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
748 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
749 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
750 xmlAddChild(catalog, node);
751 break;
752 case XML_CATA_DELEGATE_PUBLIC:
753 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
754 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
755 xmlSetProp(node, BAD_CAST "catalog", cur->value);
756 xmlAddChild(catalog, node);
757 break;
758 case XML_CATA_DELEGATE_SYSTEM:
759 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
760 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
761 xmlSetProp(node, BAD_CAST "catalog", cur->value);
762 xmlAddChild(catalog, node);
763 break;
764 case XML_CATA_URI:
765 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
766 xmlSetProp(node, BAD_CAST "name", cur->name);
767 xmlSetProp(node, BAD_CAST "uri", cur->value);
768 xmlAddChild(catalog, node);
769 break;
770 case XML_CATA_REWRITE_URI:
771 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
772 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
773 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
774 xmlAddChild(catalog, node);
775 break;
776 case XML_CATA_DELEGATE_URI:
777 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
778 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
779 xmlSetProp(node, BAD_CAST "catalog", cur->value);
780 xmlAddChild(catalog, node);
781 break;
782 case SGML_CATA_SYSTEM:
783 case SGML_CATA_PUBLIC:
784 case SGML_CATA_ENTITY:
785 case SGML_CATA_PENTITY:
786 case SGML_CATA_DOCTYPE:
787 case SGML_CATA_LINKTYPE:
788 case SGML_CATA_NOTATION:
789 case SGML_CATA_DELEGATE:
790 case SGML_CATA_BASE:
791 case SGML_CATA_CATALOG:
792 case SGML_CATA_DOCUMENT:
793 case SGML_CATA_SGMLDECL:
794 break;
795 }
796 cur = cur->next;
797 }
798
799 /*
800 * reserialize it
801 */
802 buf = xmlOutputBufferCreateFile(out, NULL);
803 if (buf == NULL) {
804 xmlFreeDoc(doc);
805 return(-1);
806 }
807 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
808
809 /*
810 * Free it
811 */
812 xmlFreeDoc(doc);
813
814 return(ret);
815}
816
817/**
818 * xmlAddXMLCatalog:
819 * @catal: top of an XML catalog
820 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +0000821 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +0000822 * @replace: the replacement value for the match
823 *
824 * Add an entry in the XML catalog, it may overwrite existing but
825 * different entries.
826 *
827 * Returns 0 if successful, -1 otherwise
828 */
829static int
830xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
831 const xmlChar *orig, const xmlChar *replace) {
832 xmlCatalogEntryPtr cur;
833 xmlCatalogEntryType typ;
834
835 if ((catal == NULL) || (catal->type != XML_CATA_CATALOG))
836 return(-1);
837 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000838 if (typ == XML_CATA_NONE) {
839 if (xmlDebugCatalogs)
840 xmlGenericError(xmlGenericErrorContext,
841 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +0000842 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000843 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000844
845 cur = catal->children;
846 /*
847 * Might be a simple "update in place"
848 */
849 if (cur != NULL) {
850 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000851 if ((orig != NULL) && (cur->type == typ) &&
852 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000853 if (xmlDebugCatalogs)
854 xmlGenericError(xmlGenericErrorContext,
855 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +0000856 if (cur->value != NULL)
857 xmlFree(cur->value);
858 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +0000859 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +0000860 }
861 if (cur->next == NULL)
862 break;
863 cur = cur->next;
864 }
865 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000866 if (xmlDebugCatalogs)
867 xmlGenericError(xmlGenericErrorContext,
868 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +0000869 if (cur == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000870 catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000871 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000872 cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillardcda96922001-08-21 10:56:31 +0000873 return(0);
874}
875
876/**
877 * xmlDelXMLCatalog:
878 * @catal: top of an XML catalog
879 * @value: the value to remove from teh catalog
880 *
881 * Remove entries in the XML catalog where the value or the URI
882 * is equal to @value
883 *
884 * Returns the number of entries removed if successful, -1 otherwise
885 */
886static int
887xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
888 xmlCatalogEntryPtr cur, prev, tmp;
889 int ret = 0;
890
891 if ((catal == NULL) || (catal->type != XML_CATA_CATALOG))
892 return(-1);
893 if (value == NULL)
894 return(-1);
895
896 /*
897 * Scan the children
898 */
899 cur = catal->children;
900 prev = NULL;
901 while (cur != NULL) {
902 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
903 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000904 if (xmlDebugCatalogs) {
905 if (cur->name != NULL)
906 xmlGenericError(xmlGenericErrorContext,
907 "Removing element %s from catalog\n", cur->name);
908 else
909 xmlGenericError(xmlGenericErrorContext,
910 "Removing element %s from catalog\n", cur->value);
911 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000912 ret++;
913 tmp = cur;
914 cur = tmp->next;
915 if (prev == NULL) {
916 catal->children = cur;
917 } else {
918 prev->next = cur;
919 }
920 xmlFreeCatalogEntry(tmp);
921 continue;
922 }
923 prev = cur;
924 cur = cur->next;
925 }
926 return(ret);
927}
928
929/**
Daniel Veillardcda96922001-08-21 10:56:31 +0000930 * xmlCatalogXMLResolve:
931 * @catal: a catalog list
932 * @pubId: the public ID string
933 * @sysId: the system ID string
934 *
935 * Do a complete resolution lookup of an External Identifier for a
936 * list of catalog entries.
937 *
938 * Implements (or tries to) 7.1. External Identifier Resolution
939 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
940 *
941 * Returns the URI of the resource or NULL if not found
942 */
943static xmlChar *
944xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
945 const xmlChar *sysID) {
946 xmlChar *ret = NULL;
947 xmlCatalogEntryPtr cur;
948 int haveDelegate = 0;
949 int haveNext = 0;
950
951 /*
952 * First tries steps 2/ 3/ 4/ if a system ID is provided.
953 */
954 if (sysID != NULL) {
955 xmlCatalogEntryPtr rewrite = NULL;
956 int lenrewrite = 0, len;
957 cur = catal;
958 haveDelegate = 0;
959 while (cur != NULL) {
960 switch (cur->type) {
961 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000962 if (xmlStrEqual(sysID, cur->name)) {
963 if (xmlDebugCatalogs)
964 xmlGenericError(xmlGenericErrorContext,
965 "Found system match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +0000966 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000967 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000968 break;
969 case XML_CATA_REWRITE_SYSTEM:
970 len = xmlStrlen(cur->name);
971 if ((len > lenrewrite) &&
972 (!xmlStrncmp(sysID, cur->name, len))) {
973 lenrewrite = len;
974 rewrite = cur;
975 }
976 break;
977 case XML_CATA_DELEGATE_SYSTEM:
978 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
979 haveDelegate++;
980 break;
981 case XML_CATA_NEXT_CATALOG:
982 haveNext++;
983 break;
984 default:
985 break;
986 }
987 cur = cur->next;
988 }
989 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000990 if (xmlDebugCatalogs)
991 xmlGenericError(xmlGenericErrorContext,
992 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardcda96922001-08-21 10:56:31 +0000993 ret = xmlStrdup(rewrite->value);
994 if (ret != NULL)
995 ret = xmlStrcat(ret, &sysID[lenrewrite]);
996 return(ret);
997 }
998 if (haveDelegate) {
999 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001000 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001001 * matches when the list was produced.
1002 */
1003 cur = catal;
1004 while (cur != NULL) {
1005 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1006 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
1007 if (cur->children == NULL) {
1008 xmlFetchXMLCatalogFile(cur);
1009 }
1010 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001011 if (xmlDebugCatalogs)
1012 xmlGenericError(xmlGenericErrorContext,
1013 "Trying system delegate %s\n", cur->value);
1014 ret = xmlCatalogListXMLResolve(cur->children, NULL,
1015 sysID);
1016 if (ret != NULL)
1017 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001018 }
1019 }
1020 cur = cur->next;
1021 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001022 /*
1023 * Apply the cut algorithm explained in 4/
1024 */
1025 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001026 }
1027 }
1028 /*
1029 * Then tries 5/ 6/ if a public ID is provided
1030 */
1031 if (pubID != NULL) {
1032 cur = catal;
1033 haveDelegate = 0;
1034 while (cur != NULL) {
1035 switch (cur->type) {
1036 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001037 if (xmlStrEqual(pubID, cur->name)) {
1038 if (xmlDebugCatalogs)
1039 xmlGenericError(xmlGenericErrorContext,
1040 "Found public match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001041 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001042 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001043 break;
1044 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001045 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1046 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001047 haveDelegate++;
1048 break;
1049 case XML_CATA_NEXT_CATALOG:
1050 if (sysID == NULL)
1051 haveNext++;
1052 break;
1053 default:
1054 break;
1055 }
1056 cur = cur->next;
1057 }
1058 if (haveDelegate) {
1059 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001060 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001061 * matches when the list was produced.
1062 */
1063 cur = catal;
1064 while (cur != NULL) {
1065 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001066 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1067 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001068 if (cur->children == NULL) {
1069 xmlFetchXMLCatalogFile(cur);
1070 }
1071 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001072 if (xmlDebugCatalogs)
1073 xmlGenericError(xmlGenericErrorContext,
1074 "Trying public delegate %s\n", cur->value);
1075 ret = xmlCatalogListXMLResolve(cur->children, pubID,
1076 NULL);
1077 if (ret != NULL)
1078 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001079 }
1080 }
1081 cur = cur->next;
1082 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001083 /*
1084 * Apply the cut algorithm explained in 4/
1085 */
1086 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001087 }
1088 }
1089 if (haveNext) {
1090 cur = catal;
1091 while (cur != NULL) {
1092 if (cur->type == XML_CATA_NEXT_CATALOG) {
1093 if (cur->children == NULL) {
1094 xmlFetchXMLCatalogFile(cur);
1095 }
1096 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001097 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1098 if (ret != NULL)
1099 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001100 }
1101 }
1102 cur = cur->next;
1103 }
1104 }
1105
1106 return(NULL);
1107}
1108
1109/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001110 * xmlCatalogXMLResolveURI:
1111 * @catal: a catalog list
1112 * @URI: the URI
1113 * @sysId: the system ID string
1114 *
1115 * Do a complete resolution lookup of an External Identifier for a
1116 * list of catalog entries.
1117 *
1118 * Implements (or tries to) 7.2.2. URI Resolution
1119 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1120 *
1121 * Returns the URI of the resource or NULL if not found
1122 */
1123static xmlChar *
1124xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1125 xmlChar *ret = NULL;
1126 xmlCatalogEntryPtr cur;
1127 int haveDelegate = 0;
1128 int haveNext = 0;
1129 xmlCatalogEntryPtr rewrite = NULL;
1130 int lenrewrite = 0, len;
1131
1132 if (catal == NULL)
1133 return(NULL);
1134
1135 if (URI == NULL)
1136 return(NULL);
1137
1138 /*
1139 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1140 */
1141 cur = catal;
1142 haveDelegate = 0;
1143 while (cur != NULL) {
1144 switch (cur->type) {
1145 case XML_CATA_URI:
1146 if (xmlStrEqual(URI, cur->name)) {
1147 if (xmlDebugCatalogs)
1148 xmlGenericError(xmlGenericErrorContext,
1149 "Found URI match %s\n", cur->name);
1150 return(xmlStrdup(cur->value));
1151 }
1152 break;
1153 case XML_CATA_REWRITE_URI:
1154 len = xmlStrlen(cur->name);
1155 if ((len > lenrewrite) &&
1156 (!xmlStrncmp(URI, cur->name, len))) {
1157 lenrewrite = len;
1158 rewrite = cur;
1159 }
1160 break;
1161 case XML_CATA_DELEGATE_URI:
1162 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1163 haveDelegate++;
1164 break;
1165 case XML_CATA_NEXT_CATALOG:
1166 haveNext++;
1167 break;
1168 default:
1169 break;
1170 }
1171 cur = cur->next;
1172 }
1173 if (rewrite != NULL) {
1174 if (xmlDebugCatalogs)
1175 xmlGenericError(xmlGenericErrorContext,
1176 "Using rewriting rule %s\n", rewrite->name);
1177 ret = xmlStrdup(rewrite->value);
1178 if (ret != NULL)
1179 ret = xmlStrcat(ret, &URI[lenrewrite]);
1180 return(ret);
1181 }
1182 if (haveDelegate) {
1183 /*
1184 * Assume the entries have been sorted by decreasing substring
1185 * matches when the list was produced.
1186 */
1187 cur = catal;
1188 while (cur != NULL) {
1189 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1190 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
1191 if (cur->children == NULL) {
1192 xmlFetchXMLCatalogFile(cur);
1193 }
1194 if (cur->children != NULL) {
1195 if (xmlDebugCatalogs)
1196 xmlGenericError(xmlGenericErrorContext,
1197 "Trying URI delegate %s\n", cur->value);
1198 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1199 if (ret != NULL)
1200 return(ret);
1201 }
1202 }
1203 cur = cur->next;
1204 }
1205 /*
1206 * Apply the cut algorithm explained in 4/
1207 */
1208 return(XML_CATAL_BREAK);
1209 }
1210 if (haveNext) {
1211 cur = catal;
1212 while (cur != NULL) {
1213 if (cur->type == XML_CATA_NEXT_CATALOG) {
1214 if (cur->children == NULL) {
1215 xmlFetchXMLCatalogFile(cur);
1216 }
1217 if (cur->children != NULL) {
1218 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1219 if (ret != NULL)
1220 return(ret);
1221 }
1222 }
1223 cur = cur->next;
1224 }
1225 }
1226
1227 return(NULL);
1228}
1229
1230/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001231 * xmlCatalogListXMLResolve:
1232 * @catal: a catalog list
1233 * @pubId: the public ID string
1234 * @sysId: the system ID string
1235 *
1236 * Do a complete resolution lookup of an External Identifier for a
1237 * list of catalogs
1238 *
1239 * Implements (or tries to) 7.1. External Identifier Resolution
1240 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1241 *
1242 * Returns the URI of the resource or NULL if not found
1243 */
1244static xmlChar *
1245xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1246 const xmlChar *sysID) {
1247 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001248 xmlChar *urnID = NULL;
1249
1250 if (catal == NULL)
1251 return(NULL);
1252 if ((pubID == NULL) && (sysID == NULL))
1253 return(NULL);
1254
1255 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1256 urnID = xmlCatalogUnWrapURN(pubID);
1257 if (xmlDebugCatalogs) {
1258 if (urnID == NULL)
1259 xmlGenericError(xmlGenericErrorContext,
1260 "Public URN ID %s expanded to NULL\n", pubID);
1261 else
1262 xmlGenericError(xmlGenericErrorContext,
1263 "Public URN ID expanded to %s\n", urnID);
1264 }
1265 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1266 if (urnID != NULL)
1267 xmlFree(urnID);
1268 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001269 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001270 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1271 urnID = xmlCatalogUnWrapURN(sysID);
1272 if (xmlDebugCatalogs) {
1273 if (urnID == NULL)
1274 xmlGenericError(xmlGenericErrorContext,
1275 "System URN ID %s expanded to NULL\n", sysID);
1276 else
1277 xmlGenericError(xmlGenericErrorContext,
1278 "System URN ID expanded to %s\n", urnID);
1279 }
1280 if (pubID == NULL)
1281 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1282 else if (xmlStrEqual(pubID, urnID))
1283 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1284 else {
1285 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1286 }
1287 if (urnID != NULL)
1288 xmlFree(urnID);
1289 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001290 }
1291 while (catal != NULL) {
1292 if (catal->type == XML_CATA_CATALOG) {
1293 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001294 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001295 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001296 if (catal->children != NULL) {
1297 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1298 if (ret != NULL)
1299 return(ret);
1300 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001301 }
1302 catal = catal->next;
1303 }
1304 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001305}
1306
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001307/**
1308 * xmlCatalogListXMLResolveURI:
1309 * @catal: a catalog list
1310 * @URI: the URI
1311 *
1312 * Do a complete resolution lookup of an URI for a list of catalogs
1313 *
1314 * Implements (or tries to) 7.2. URI Resolution
1315 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1316 *
1317 * Returns the URI of the resource or NULL if not found
1318 */
1319static xmlChar *
1320xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1321 xmlChar *ret = NULL;
1322 xmlChar *urnID = NULL;
1323
1324 if (catal == NULL)
1325 return(NULL);
1326 if (URI == NULL)
1327 return(NULL);
1328
1329 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1330 urnID = xmlCatalogUnWrapURN(URI);
1331 if (xmlDebugCatalogs) {
1332 if (urnID == NULL)
1333 xmlGenericError(xmlGenericErrorContext,
1334 "URN ID %s expanded to NULL\n", URI);
1335 else
1336 xmlGenericError(xmlGenericErrorContext,
1337 "URN ID expanded to %s\n", urnID);
1338 }
1339 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1340 if (urnID != NULL)
1341 xmlFree(urnID);
1342 return(ret);
1343 }
1344 while (catal != NULL) {
1345 if (catal->type == XML_CATA_CATALOG) {
1346 if (catal->children == NULL) {
1347 xmlFetchXMLCatalogFile(catal);
1348 }
1349 if (catal->children != NULL) {
1350 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1351 if (ret != NULL)
1352 return(ret);
1353 }
1354 }
1355 catal = catal->next;
1356 }
1357 return(ret);
1358}
1359
Daniel Veillard344cee72001-08-20 00:08:40 +00001360/************************************************************************
1361 * *
1362 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001363 * *
1364 ************************************************************************/
1365
1366
1367#define RAW *cur
1368#define NEXT cur++;
1369#define SKIP(x) cur += x;
1370
1371#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1372
1373static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001374xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001375 if ((cur[0] != '-') || (cur[1] != '-'))
1376 return(cur);
1377 SKIP(2);
1378 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1379 NEXT;
1380 if (cur[0] == 0) {
1381 return(NULL);
1382 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001383 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001384}
1385
1386static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001387xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001388 xmlChar *buf = NULL;
1389 int len = 0;
1390 int size = 50;
1391 xmlChar stop;
1392 int count = 0;
1393
1394 *id = NULL;
1395
1396 if (RAW == '"') {
1397 NEXT;
1398 stop = '"';
1399 } else if (RAW == '\'') {
1400 NEXT;
1401 stop = '\'';
1402 } else {
1403 stop = ' ';
1404 }
1405 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1406 if (buf == NULL) {
1407 xmlGenericError(xmlGenericErrorContext,
1408 "malloc of %d byte failed\n", size);
1409 return(NULL);
1410 }
1411 while (xmlIsPubidChar(*cur)) {
1412 if ((*cur == stop) && (stop != ' '))
1413 break;
1414 if ((stop == ' ') && (IS_BLANK(*cur)))
1415 break;
1416 if (len + 1 >= size) {
1417 size *= 2;
1418 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1419 if (buf == NULL) {
1420 xmlGenericError(xmlGenericErrorContext,
1421 "realloc of %d byte failed\n", size);
1422 return(NULL);
1423 }
1424 }
1425 buf[len++] = *cur;
1426 count++;
1427 NEXT;
1428 }
1429 buf[len] = 0;
1430 if (stop == ' ') {
1431 if (!IS_BLANK(*cur)) {
1432 xmlFree(buf);
1433 return(NULL);
1434 }
1435 } else {
1436 if (*cur != stop) {
1437 xmlFree(buf);
1438 return(NULL);
1439 }
1440 NEXT;
1441 }
1442 *id = buf;
1443 return(cur);
1444}
1445
1446static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001447xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001448 xmlChar buf[XML_MAX_NAMELEN + 5];
1449 int len = 0;
1450 int c;
1451
1452 *name = NULL;
1453
1454 /*
1455 * Handler for more complex cases
1456 */
1457 c = *cur;
1458 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
1459 return(NULL);
1460 }
1461
1462 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
1463 (c == '.') || (c == '-') ||
1464 (c == '_') || (c == ':'))) {
1465 buf[len++] = c;
1466 cur++;
1467 c = *cur;
1468 if (len >= XML_MAX_NAMELEN)
1469 return(NULL);
1470 }
1471 *name = xmlStrndup(buf, len);
1472 return(cur);
1473}
1474
Daniel Veillard344cee72001-08-20 00:08:40 +00001475static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00001476xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001477 xmlCatalogEntryType type = XML_CATA_NONE;
1478 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
1479 type = SGML_CATA_SYSTEM;
1480 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
1481 type = SGML_CATA_PUBLIC;
1482 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1483 type = SGML_CATA_DELEGATE;
1484 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
1485 type = SGML_CATA_ENTITY;
1486 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
1487 type = SGML_CATA_DOCTYPE;
1488 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
1489 type = SGML_CATA_LINKTYPE;
1490 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
1491 type = SGML_CATA_NOTATION;
1492 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
1493 type = SGML_CATA_SGMLDECL;
1494 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
1495 type = SGML_CATA_DOCUMENT;
1496 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
1497 type = SGML_CATA_CATALOG;
1498 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
1499 type = SGML_CATA_BASE;
1500 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1501 type = SGML_CATA_DELEGATE;
1502 return(type);
1503}
1504
Daniel Veillarda7374592001-05-10 14:17:55 +00001505static int
Daniel Veillardcda96922001-08-21 10:56:31 +00001506xmlParseSGMLCatalog(const xmlChar *value, const char *file) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001507 const xmlChar *cur = value;
1508 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001509 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00001510
1511 if ((cur == NULL) || (file == NULL))
1512 return(-1);
1513 base = xmlStrdup((const xmlChar *) file);
1514
1515 while ((cur != NULL) && (cur[0] != '0')) {
1516 SKIP_BLANKS;
1517 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001518 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00001519 if (cur == NULL) {
1520 /* error */
1521 break;
1522 }
1523 } else {
1524 xmlChar *sysid = NULL;
1525 xmlChar *name = NULL;
1526 xmlCatalogEntryType type = XML_CATA_NONE;
1527
Daniel Veillardcda96922001-08-21 10:56:31 +00001528 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001529 if (name == NULL) {
1530 /* error */
1531 break;
1532 }
1533 if (!IS_BLANK(*cur)) {
1534 /* error */
1535 break;
1536 }
1537 SKIP_BLANKS;
1538 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001539 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00001540 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001541 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00001542 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001543 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001544 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001545 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00001546 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001547 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001548 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001549 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001550 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001551 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00001552 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001553 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001554 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001555 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00001556 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001557 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00001558 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001559 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001560 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001561 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001562 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
1563 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001564 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001565 if (name == NULL) {
1566 /* error */
1567 break;
1568 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001569 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001570 continue;
1571 }
1572 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001573 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001574
1575 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001576 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00001577 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00001578 type = SGML_CATA_PENTITY;
1579 case SGML_CATA_PENTITY:
1580 case SGML_CATA_DOCTYPE:
1581 case SGML_CATA_LINKTYPE:
1582 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00001583 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001584 if (cur == NULL) {
1585 /* error */
1586 break;
1587 }
1588 if (!IS_BLANK(*cur)) {
1589 /* error */
1590 break;
1591 }
1592 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001593 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001594 if (cur == NULL) {
1595 /* error */
1596 break;
1597 }
1598 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001599 case SGML_CATA_PUBLIC:
1600 case SGML_CATA_SYSTEM:
1601 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00001602 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001603 if (cur == NULL) {
1604 /* error */
1605 break;
1606 }
1607 if (!IS_BLANK(*cur)) {
1608 /* error */
1609 break;
1610 }
1611 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001612 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001613 if (cur == NULL) {
1614 /* error */
1615 break;
1616 }
1617 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001618 case SGML_CATA_BASE:
1619 case SGML_CATA_CATALOG:
1620 case SGML_CATA_DOCUMENT:
1621 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00001622 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001623 if (cur == NULL) {
1624 /* error */
1625 break;
1626 }
1627 break;
1628 default:
1629 break;
1630 }
1631 if (cur == NULL) {
1632 if (name != NULL)
1633 xmlFree(name);
1634 if (sysid != NULL)
1635 xmlFree(sysid);
1636 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001637 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001638 if (base != NULL)
1639 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001640 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00001641 } else if ((type == SGML_CATA_PUBLIC) ||
1642 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001643 xmlChar *filename;
1644
1645 filename = xmlBuildURI(sysid, base);
1646 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001647 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00001648
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001649 entry = xmlNewCatalogEntry(type, name, filename,
1650 XML_CATA_PREFER_NONE);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001651 res = xmlHashAddEntry(xmlDefaultCatalog, name, entry);
1652 if (res < 0) {
1653 xmlFreeCatalogEntry(entry);
1654 }
1655 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00001656 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001657
Daniel Veillard344cee72001-08-20 00:08:40 +00001658 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001659 xmlChar *filename;
1660
1661 filename = xmlBuildURI(sysid, base);
1662 if (filename != NULL) {
1663 xmlLoadCatalog((const char *)filename);
1664 xmlFree(filename);
1665 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001666 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001667 /*
1668 * drop anything else we won't handle it
1669 */
1670 if (name != NULL)
1671 xmlFree(name);
1672 if (sysid != NULL)
1673 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001674 }
1675 }
1676 if (base != NULL)
1677 xmlFree(base);
1678 if (cur == NULL)
1679 return(-1);
1680 return(0);
1681}
1682
Daniel Veillardcda96922001-08-21 10:56:31 +00001683/**
1684 * xmlCatalogGetSGMLPublic:
1685 * @catal: an SGML catalog hash
1686 * @pubId: the public ID string
1687 *
1688 * Try to lookup the system ID associated to a public ID
1689 *
1690 * Returns the system ID if found or NULL otherwise.
1691 */
1692static const xmlChar *
1693xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
1694 xmlCatalogEntryPtr entry;
1695
1696 if (catal == NULL)
1697 return(NULL);
1698
1699 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
1700 if (entry == NULL)
1701 return(NULL);
1702 if (entry->type == SGML_CATA_PUBLIC)
1703 return(entry->value);
1704 return(NULL);
1705}
1706
1707/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001708 * xmlCatalogGetSGMLSystem:
1709 * @catal: an SGML catalog hash
1710 * @sysId: the public ID string
1711 *
1712 * Try to lookup the catalog local reference for a system ID
1713 *
1714 * Returns the system ID if found or NULL otherwise.
1715 */
1716static const xmlChar *
1717xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
1718 xmlCatalogEntryPtr entry;
1719
1720 if (catal == NULL)
1721 return(NULL);
1722
1723 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
1724 if (entry == NULL)
1725 return(NULL);
1726 if (entry->type == SGML_CATA_SYSTEM)
1727 return(entry->value);
1728 return(NULL);
1729}
1730
1731/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001732 * xmlCatalogSGMLResolve:
1733 * @pubId: the public ID string
1734 * @sysId: the system ID string
1735 *
1736 * Do a complete resolution lookup of an External Identifier
1737 *
1738 * Returns the URI of the resource or NULL if not found
1739 */
1740static const xmlChar *
1741xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00001742 const xmlChar *ret = NULL;
1743
1744 if (xmlDefaultCatalog == NULL)
1745 return(NULL);
1746
1747 if (pubID != NULL)
1748 ret = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
1749 if (ret != NULL)
1750 return(ret);
1751 if (sysID != NULL)
1752 ret = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00001753 return(NULL);
1754}
1755
Daniel Veillarda7374592001-05-10 14:17:55 +00001756/************************************************************************
1757 * *
1758 * Public interfaces *
1759 * *
1760 ************************************************************************/
1761
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001762/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001763 * xmlInitializeCatalog:
1764 *
1765 * Do the catalog initialization.
1766 * TODO: this function is not thread safe, catalog initialization should
1767 * preferably be done once at startup
1768 */
1769void
1770xmlInitializeCatalog(void) {
1771 const char *catalogs;
1772
1773 if (xmlCatalogInitialized != 0)
1774 return;
1775
1776 if (getenv("XML_DEBUG_CATALOG"))
1777 xmlDebugCatalogs = 1;
1778 if ((xmlDefaultXMLCatalogList == NULL) && (xmlDefaultCatalog == NULL)) {
1779 catalogs = getenv("XML_CATALOG_FILES");
1780 if (catalogs == NULL)
1781 catalogs = XML_DEFAULT_CATALOG;
1782 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
1783 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
1784 }
1785
1786 xmlCatalogInitialized = 1;
1787}
1788
1789/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001790 * xmlLoadCatalog:
1791 * @filename: a file path
1792 *
Daniel Veillard81418e32001-05-22 15:08:55 +00001793 * Load the catalog and makes its definitions effective for the default
1794 * external entity loader. It will recuse in CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001795 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001796 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00001797 *
1798 * Returns 0 in case of success -1 in case of error
1799 */
1800int
1801xmlLoadCatalog(const char *filename) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001802 int fd, len, ret, i;
Daniel Veillarda7374592001-05-10 14:17:55 +00001803 struct stat info;
1804 xmlChar *content;
1805
1806 if (filename == NULL)
1807 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001808
Daniel Veillarda7374592001-05-10 14:17:55 +00001809 if (xmlDefaultCatalog == NULL)
1810 xmlDefaultCatalog = xmlHashCreate(20);
1811 if (xmlDefaultCatalog == NULL)
1812 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001813
1814 /*
1815 * Need to be done after ...
1816 */
1817 if (!xmlCatalogInitialized)
1818 xmlInitializeCatalog();
1819
1820#ifdef HAVE_STAT
Daniel Veillarda7374592001-05-10 14:17:55 +00001821 if (stat(filename, &info) < 0)
1822 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001823#endif
Daniel Veillarda7374592001-05-10 14:17:55 +00001824
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001825 /*
1826 * Prevent loops
1827 */
1828 for (i = 0;i < catalNr;i++) {
Daniel Veillard81418e32001-05-22 15:08:55 +00001829 if (xmlStrEqual((const xmlChar *)catalTab[i],
1830 (const xmlChar *)filename)) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001831 xmlGenericError(xmlGenericErrorContext,
1832 "xmlLoadCatalog: %s seems to induce a loop\n",
1833 filename);
1834 return(-1);
1835 }
1836 }
1837 if (catalNr >= catalMax) {
1838 xmlGenericError(xmlGenericErrorContext,
1839 "xmlLoadCatalog: %s catalog list too deep\n",
1840 filename);
1841 return(-1);
1842 }
1843 catalTab[catalNr++] = filename;
1844
1845 if ((fd = open(filename, O_RDONLY)) < 0) {
1846 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001847 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001848 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001849
1850 content = xmlMalloc(info.st_size + 10);
1851 if (content == NULL) {
1852 xmlGenericError(xmlGenericErrorContext,
1853 "realloc of %d byte failed\n", info.st_size + 10);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001854 catalNr--;
1855 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00001856 }
1857 len = read(fd, content, info.st_size);
1858 if (len < 0) {
1859 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001860 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001861 return(-1);
1862 }
1863 content[len] = 0;
1864 close(fd);
1865
Daniel Veillard344cee72001-08-20 00:08:40 +00001866 if ((content[0] == ' ') || (content[0] == '-') ||
1867 ((content[0] >= 'A') && (content[0] <= 'Z')) ||
1868 ((content[0] >= 'a') && (content[0] <= 'z')))
Daniel Veillardcda96922001-08-21 10:56:31 +00001869 ret = xmlParseSGMLCatalog(content, filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001870 else {
1871 xmlCatalogEntryPtr catal, tmp;
1872 /* TODO: allow to switch the default preference */
1873 catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
1874 if (catal != NULL) {
1875 if (xmlDefaultXMLCatalogList == NULL)
1876 xmlDefaultXMLCatalogList = catal;
1877 else {
1878 tmp = xmlDefaultXMLCatalogList;
1879 while (tmp->next != NULL)
1880 tmp = tmp->next;
1881 tmp->next = catal;
1882 }
1883 ret = 0;
1884 } else
1885 ret = -1;
1886 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001887 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001888 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001889 return(ret);
1890}
1891
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001892/**
Daniel Veillard81418e32001-05-22 15:08:55 +00001893 * xmlLoadCatalogs:
1894 * @paths: a list of file path separated by ':' or spaces
1895 *
1896 * Load the catalogs and makes their definitions effective for the default
1897 * external entity loader.
1898 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001899 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00001900 */
1901void
1902xmlLoadCatalogs(const char *pathss) {
1903 const char *cur;
1904 const char *paths;
1905 xmlChar *path;
1906
1907 cur = pathss;
1908 while ((cur != NULL) && (*cur != 0)) {
1909 while (IS_BLANK(*cur)) cur++;
1910 if (*cur != 0) {
1911 paths = cur;
1912 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
1913 cur++;
1914 path = xmlStrndup((const xmlChar *)paths, cur - paths);
1915 if (path != NULL) {
1916 xmlLoadCatalog((const char *) path);
1917 xmlFree(path);
1918 }
1919 }
1920 while (*cur == ':')
1921 cur++;
1922 }
1923}
1924
Daniel Veillarda7374592001-05-10 14:17:55 +00001925/**
1926 * xmlCatalogCleanup:
1927 *
1928 * Free up all the memory associated with catalogs
1929 */
1930void
1931xmlCatalogCleanup(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001932 if (xmlDebugCatalogs)
1933 xmlGenericError(xmlGenericErrorContext,
1934 "Catalogs cleanup\n");
Daniel Veillardcda96922001-08-21 10:56:31 +00001935 if (xmlDefaultXMLCatalogList != NULL)
1936 xmlFreeCatalogEntryList(xmlDefaultXMLCatalogList);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001937 xmlDefaultXMLCatalogList = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001938 if (xmlDefaultCatalog != NULL)
1939 xmlHashFree(xmlDefaultCatalog,
1940 (xmlHashDeallocator) xmlFreeCatalogEntry);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001941 xmlDebugCatalogs = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00001942 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001943 xmlCatalogInitialized = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00001944}
1945
1946/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001947 * xmlCatalogGetSystem:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001948 * @pubId: the public ID string
Daniel Veillarda7374592001-05-10 14:17:55 +00001949 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001950 * Try to lookup the system ID associated to a public ID
1951 * DEPRECATED, use xmlCatalogResolveSystem()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001952 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001953 * Returns the system ID if found or NULL otherwise.
Daniel Veillarda7374592001-05-10 14:17:55 +00001954 */
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001955const xmlChar *
1956xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001957 xmlChar *ret;
1958 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001959
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001960 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001961 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001962
1963 if (!xmlCatalogInitialized)
1964 xmlInitializeCatalog();
1965
1966 /*
1967 * Check first the XML catalogs
1968 */
1969 if (xmlDefaultXMLCatalogList != NULL) {
1970 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
1971 if (ret != NULL) {
1972 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
1973 result[sizeof(result) - 1] = 0;
1974 return(result);
1975 }
1976 }
1977
1978 if (xmlDefaultCatalog != NULL)
1979 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID));
1980 return(NULL);
1981}
1982
1983/**
1984 * xmlCatalogResolveSystem:
1985 * @sysId: the public ID string
1986 *
1987 * Try to lookup the catalog resource for a system ID
1988 *
1989 * Returns the system ID if found or NULL otherwise, the value returned
1990 * must be freed by the caller.
1991 */
1992xmlChar *
1993xmlCatalogResolveSystem(const xmlChar *sysID) {
1994 xmlCatalogEntryPtr catal;
1995 xmlChar *ret;
1996 const xmlChar *sgml;
1997
1998 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001999 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002000
2001 if (!xmlCatalogInitialized)
2002 xmlInitializeCatalog();
2003
2004 /*
2005 * Check first the XML catalogs
2006 */
2007 catal = xmlDefaultXMLCatalogList;
2008 if (catal != NULL) {
2009 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
2010 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2011 return(ret);
2012 }
2013
2014 if (xmlDefaultCatalog != NULL) {
2015 sgml = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
2016 if (sgml != NULL)
2017 return(xmlStrdup(sgml));
2018 }
Daniel Veillard344cee72001-08-20 00:08:40 +00002019 return(NULL);
2020}
2021
2022/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002023 * xmlCatalogGetPublic:
2024 * @pubId: the public ID string
2025 *
2026 * Try to lookup the system ID associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002027 * DEPRECATED, use xmlCatalogResolvePublic()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002028 *
2029 * Returns the system ID if found or NULL otherwise.
2030 */
2031const xmlChar *
2032xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002033 xmlChar *ret;
2034 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002035
Daniel Veillard344cee72001-08-20 00:08:40 +00002036 if (pubID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002037 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00002038
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002039 if (!xmlCatalogInitialized)
2040 xmlInitializeCatalog();
2041
2042 /*
2043 * Check first the XML catalogs
2044 */
2045 if (xmlDefaultXMLCatalogList != NULL) {
2046 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2047 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
2048 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
2049 result[sizeof(result) - 1] = 0;
2050 return(result);
2051 }
2052 }
2053
2054 if (xmlDefaultCatalog != NULL)
2055 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
2056 return(NULL);
2057}
2058
2059/**
2060 * xmlCatalogResolvePublic:
2061 * @pubId: the public ID string
2062 *
2063 * Try to lookup the system ID associated to a public ID
2064 *
2065 * Returns the system ID if found or NULL otherwise, the value returned
2066 * must be freed by the caller.
2067 */
2068xmlChar *
2069xmlCatalogResolvePublic(const xmlChar *pubID) {
2070 xmlCatalogEntryPtr catal;
2071 xmlChar *ret;
2072 const xmlChar *sgml;
2073
2074 if (pubID == NULL)
2075 return(NULL);
2076
2077 if (!xmlCatalogInitialized)
2078 xmlInitializeCatalog();
2079
Daniel Veillard344cee72001-08-20 00:08:40 +00002080 /*
2081 * Check first the XML catalogs
2082 */
2083 catal = xmlDefaultXMLCatalogList;
2084 if (catal != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002085 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2086 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
Daniel Veillard344cee72001-08-20 00:08:40 +00002087 return(ret);
2088 }
2089
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002090 if (xmlDefaultCatalog != NULL) {
2091 sgml = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
2092 if (sgml != NULL)
2093 return(xmlStrdup(sgml));
2094 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002095 return(NULL);
2096}
Daniel Veillard344cee72001-08-20 00:08:40 +00002097
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002098/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002099 * xmlCatalogResolve:
2100 * @pubId: the public ID string
2101 * @sysId: the system ID string
2102 *
2103 * Do a complete resolution lookup of an External Identifier
2104 *
2105 * Returns the URI of the resource or NULL if not found, it must be freed
2106 * by the caller.
2107 */
2108xmlChar *
2109xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002110 if (!xmlCatalogInitialized)
2111 xmlInitializeCatalog();
2112
Daniel Veillardcda96922001-08-21 10:56:31 +00002113 if (xmlDefaultXMLCatalogList != NULL) {
2114 return(xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, sysID));
2115 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002116 const xmlChar *ret;
2117
2118 ret = xmlCatalogSGMLResolve(pubID, sysID);
2119 if (ret != NULL)
2120 return(xmlStrdup(ret));
Daniel Veillardcda96922001-08-21 10:56:31 +00002121 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002122 return(NULL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002123}
2124
2125/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002126 * xmlCatalogResolveURI:
2127 * @pubId: the URI
2128 *
2129 * Do a complete resolution lookup of an URI
2130 *
2131 * Returns the URI of the resource or NULL if not found, it must be freed
2132 * by the caller.
2133 */
2134xmlChar *
2135xmlCatalogResolveURI(const xmlChar *URI) {
2136 if (!xmlCatalogInitialized)
2137 xmlInitializeCatalog();
2138
2139 if (xmlDefaultXMLCatalogList != NULL) {
2140 return(xmlCatalogListXMLResolveURI(xmlDefaultXMLCatalogList, URI));
2141 } else {
2142 const xmlChar *ret;
2143
2144 ret = xmlCatalogSGMLResolve(NULL, URI);
2145 if (ret != NULL)
2146 return(xmlStrdup(ret));
2147 }
2148 return(NULL);
2149}
2150
2151/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002152 * xmlCatalogDump:
2153 * @out: the file.
2154 *
2155 * Free up all the memory associated with catalogs
2156 */
2157void
2158xmlCatalogDump(FILE *out) {
2159 if (out == NULL)
2160 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00002161
2162 if (xmlDefaultXMLCatalogList != NULL) {
2163 xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList);
2164 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002165 xmlHashScan(xmlDefaultCatalog,
2166 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00002167 }
2168}
2169
2170/**
2171 * xmlCatalogAdd:
2172 * @type: the type of record to add to the catalog
2173 * @orig: the system, public or prefix to match
2174 * @replace: the replacement value for the match
2175 *
2176 * Add an entry in the catalog, it may overwrite existing but
2177 * different entries.
2178 *
2179 * Returns 0 if successful, -1 otherwise
2180 */
2181int
2182xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
2183 int res = -1;
2184
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00002185 if ((xmlDefaultXMLCatalogList == NULL) &&
2186 (xmlStrEqual(type, BAD_CAST "catalog"))) {
2187 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2188 orig, xmlCatalogDefaultPrefer);
2189 return(0);
2190 }
2191
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002192 if (!xmlCatalogInitialized)
2193 xmlInitializeCatalog();
2194
Daniel Veillard344cee72001-08-20 00:08:40 +00002195 if (xmlDefaultXMLCatalogList != NULL) {
2196 res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
2197 } else if (xmlDefaultCatalog != NULL) {
2198 xmlCatalogEntryType typ;
2199
Daniel Veillardcda96922001-08-21 10:56:31 +00002200 typ = xmlGetSGMLCatalogEntryType(type);
Daniel Veillard344cee72001-08-20 00:08:40 +00002201 if (type != XML_CATA_NONE) {
2202 xmlCatalogEntryPtr entry;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002203 entry = xmlNewCatalogEntry(typ, orig, replace, XML_CATA_PREFER_NONE);
Daniel Veillard344cee72001-08-20 00:08:40 +00002204 res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
2205 }
2206 }
2207 return(res);
2208}
2209
2210/**
2211 * xmlCatalogRemove:
2212 * @value: the value to remove
2213 *
2214 * Remove an entry from the catalog
2215 *
2216 * Returns 0 if successful, -1 otherwise
2217 */
2218int
2219xmlCatalogRemove(const xmlChar *value) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002220 int res = -1;
2221
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002222 if (!xmlCatalogInitialized)
2223 xmlInitializeCatalog();
2224
Daniel Veillardcda96922001-08-21 10:56:31 +00002225 if (xmlDefaultXMLCatalogList != NULL) {
2226 res = xmlDelXMLCatalog(xmlDefaultXMLCatalogList, value);
2227 } else if (xmlDefaultCatalog != NULL) {
2228 TODO
2229 }
2230 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00002231}
2232
2233/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002234 * xmlCatalogGetDefaults:
2235 *
2236 * Used to get the user preference w.r.t. to what catalogs should
2237 * be accepted
2238 *
2239 * Returns the current xmlCatalogAllow value
2240 */
2241xmlCatalogAllow
2242xmlCatalogGetDefaults(void) {
2243 return(xmlCatalogDefaultAllow);
2244}
2245
2246/**
2247 * xmlCatalogSetDefaults:
2248 *
2249 * Used to set the user preference w.r.t. to what catalogs should
2250 * be accepted
2251 */
2252void
2253xmlCatalogSetDefaults(xmlCatalogAllow allow) {
2254 if (!xmlCatalogInitialized)
2255 xmlInitializeCatalog();
2256 if (xmlDebugCatalogs) {
2257 switch (allow) {
2258 case XML_CATA_ALLOW_NONE:
2259 xmlGenericError(xmlGenericErrorContext,
2260 "Disabling catalog usage\n");
2261 break;
2262 case XML_CATA_ALLOW_GLOBAL:
2263 xmlGenericError(xmlGenericErrorContext,
2264 "Allowing only global catalogs\n");
2265 break;
2266 case XML_CATA_ALLOW_DOCUMENT:
2267 xmlGenericError(xmlGenericErrorContext,
2268 "Allowing only catalogs from the document\n");
2269 break;
2270 case XML_CATA_ALLOW_ALL:
2271 xmlGenericError(xmlGenericErrorContext,
2272 "Allowing all catalogs\n");
2273 break;
2274 }
2275 }
2276 xmlCatalogDefaultAllow = allow;
2277}
2278
2279/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002280 * xmlCatalogSetDefaultPrefer:
2281 * @prefer: the default preference for delegation
2282 *
2283 * Allows to set the preference between public and system for deletion
2284 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002285 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002286 *
2287 * Returns the previous value of the default preference for delegation
2288 */
2289xmlCatalogPrefer
2290xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
2291 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
2292
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002293 if (!xmlCatalogInitialized)
2294 xmlInitializeCatalog();
2295 if (prefer == XML_CATA_PREFER_NONE)
2296 return(ret);
2297
2298 if (xmlDebugCatalogs) {
2299 switch (prefer) {
2300 case XML_CATA_PREFER_PUBLIC:
2301 xmlGenericError(xmlGenericErrorContext,
2302 "Setting catalog preference to PUBLIC\n");
2303 break;
2304 case XML_CATA_PREFER_SYSTEM:
2305 xmlGenericError(xmlGenericErrorContext,
2306 "Setting catalog preference to SYSTEM\n");
2307 break;
2308 case XML_CATA_PREFER_NONE:
2309 break;
2310 }
2311 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002312 xmlCatalogDefaultPrefer = prefer;
2313 return(ret);
2314}
2315
2316/**
Daniel Veillard344cee72001-08-20 00:08:40 +00002317 * xmlCatalogSetDebug:
2318 * @level: the debug level of catalogs required
2319 *
2320 * Used to set the debug level for catalog operation, 0 disable
2321 * debugging, 1 enable it
2322 *
2323 * Returns the previous value of the catalog debugging level
2324 */
2325int
2326xmlCatalogSetDebug(int level) {
2327 int ret = xmlDebugCatalogs;
2328
2329 if (level <= 0)
2330 xmlDebugCatalogs = 0;
2331 else
2332 xmlDebugCatalogs = level;
2333 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002334}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002335
2336/**
2337 * xmlCatalogFreeLocal:
2338 * @catalogs: a document's list of catalogs
2339 *
2340 * Free up the memory associated to the catalog list
2341 */
2342void
2343xmlCatalogFreeLocal(void *catalogs) {
2344 xmlCatalogEntryPtr catal;
2345
2346 catal = (xmlCatalogEntryPtr) catalogs;
2347 if (catal != NULL)
2348 xmlFreeCatalogEntryList(catal);
2349}
2350
2351
2352/**
2353 * xmlCatalogAddLocal:
2354 * @catalogs: a document's list of catalogs
2355 * @URL: the URL to a new local catalog
2356 *
2357 * Add the new entry to the catalog list
2358 *
2359 * Returns the updated list
2360 */
2361void *
2362xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
2363 xmlCatalogEntryPtr catal, add;
2364
2365 if (!xmlCatalogInitialized)
2366 xmlInitializeCatalog();
2367 if (URL == NULL)
2368 return(catalogs);
2369
2370 if (xmlDebugCatalogs)
2371 xmlGenericError(xmlGenericErrorContext,
2372 "Adding document catalog %s\n", URL);
2373
2374 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
2375 xmlCatalogDefaultPrefer);
2376 if (add == NULL)
2377 return(catalogs);
2378
2379 catal = (xmlCatalogEntryPtr) catalogs;
2380 if (catal == NULL)
2381 return((void *) add);
2382
2383 while (catal->next != NULL)
2384 catal = catal->next;
2385 catal->next = add;
2386 return(catalogs);
2387}
2388
2389/**
2390 * xmlCatalogLocalResolve:
2391 * @catalogs: a document's list of catalogs
2392 * @pubId: the public ID string
2393 * @sysId: the system ID string
2394 *
2395 * Do a complete resolution lookup of an External Identifier using a
2396 * document's private catalog list
2397 *
2398 * Returns the URI of the resource or NULL if not found, it must be freed
2399 * by the caller.
2400 */
2401xmlChar *
2402xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
2403 const xmlChar *sysID) {
2404 xmlCatalogEntryPtr catal;
2405
2406 if (!xmlCatalogInitialized)
2407 xmlInitializeCatalog();
2408 catal = (xmlCatalogEntryPtr) catalogs;
2409 if (catal == NULL)
2410 return(NULL);
2411 return(xmlCatalogListXMLResolve(catal, pubID, sysID));
2412}
2413
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002414/**
2415 * xmlCatalogLocalResolveURI:
2416 * @catalogs: a document's list of catalogs
2417 * @pubId: the URI
2418 *
2419 * Do a complete resolution lookup of an URI using a
2420 * document's private catalog list
2421 *
2422 * Returns the URI of the resource or NULL if not found, it must be freed
2423 * by the caller.
2424 */
2425xmlChar *
2426xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
2427 xmlCatalogEntryPtr catal;
2428
2429 if (!xmlCatalogInitialized)
2430 xmlInitializeCatalog();
2431 catal = (xmlCatalogEntryPtr) catalogs;
2432 if (catal == NULL)
2433 return(NULL);
2434 return(xmlCatalogListXMLResolveURI(catal, URI));
2435}
2436
Daniel Veillarda7374592001-05-10 14:17:55 +00002437#endif /* LIBXML_CATALOG_ENABLED */