blob: 2fec3b4d59a80d753245c50b359845c09332305c [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
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00001515 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001516 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00001517 if (cur[0] == 0)
1518 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00001519 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001520 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00001521 if (cur == NULL) {
1522 /* error */
1523 break;
1524 }
1525 } else {
1526 xmlChar *sysid = NULL;
1527 xmlChar *name = NULL;
1528 xmlCatalogEntryType type = XML_CATA_NONE;
1529
Daniel Veillardcda96922001-08-21 10:56:31 +00001530 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001531 if (name == NULL) {
1532 /* error */
1533 break;
1534 }
1535 if (!IS_BLANK(*cur)) {
1536 /* error */
1537 break;
1538 }
1539 SKIP_BLANKS;
1540 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001541 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00001542 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001543 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00001544 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001545 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001546 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001547 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00001548 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001549 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001550 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001551 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001552 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001553 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00001554 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001555 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001556 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001557 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00001558 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001559 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00001560 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001561 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001562 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001563 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001564 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
1565 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001566 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001567 if (name == NULL) {
1568 /* error */
1569 break;
1570 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001571 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001572 continue;
1573 }
1574 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001575 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001576
1577 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001578 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00001579 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00001580 type = SGML_CATA_PENTITY;
1581 case SGML_CATA_PENTITY:
1582 case SGML_CATA_DOCTYPE:
1583 case SGML_CATA_LINKTYPE:
1584 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00001585 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001586 if (cur == NULL) {
1587 /* error */
1588 break;
1589 }
1590 if (!IS_BLANK(*cur)) {
1591 /* error */
1592 break;
1593 }
1594 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001595 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001596 if (cur == NULL) {
1597 /* error */
1598 break;
1599 }
1600 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001601 case SGML_CATA_PUBLIC:
1602 case SGML_CATA_SYSTEM:
1603 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00001604 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001605 if (cur == NULL) {
1606 /* error */
1607 break;
1608 }
1609 if (!IS_BLANK(*cur)) {
1610 /* error */
1611 break;
1612 }
1613 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001614 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001615 if (cur == NULL) {
1616 /* error */
1617 break;
1618 }
1619 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001620 case SGML_CATA_BASE:
1621 case SGML_CATA_CATALOG:
1622 case SGML_CATA_DOCUMENT:
1623 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00001624 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001625 if (cur == NULL) {
1626 /* error */
1627 break;
1628 }
1629 break;
1630 default:
1631 break;
1632 }
1633 if (cur == NULL) {
1634 if (name != NULL)
1635 xmlFree(name);
1636 if (sysid != NULL)
1637 xmlFree(sysid);
1638 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001639 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001640 if (base != NULL)
1641 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001642 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00001643 } else if ((type == SGML_CATA_PUBLIC) ||
1644 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001645 xmlChar *filename;
1646
1647 filename = xmlBuildURI(sysid, base);
1648 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001649 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00001650
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001651 entry = xmlNewCatalogEntry(type, name, filename,
1652 XML_CATA_PREFER_NONE);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001653 res = xmlHashAddEntry(xmlDefaultCatalog, name, entry);
1654 if (res < 0) {
1655 xmlFreeCatalogEntry(entry);
1656 }
1657 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00001658 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001659
Daniel Veillard344cee72001-08-20 00:08:40 +00001660 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001661 xmlChar *filename;
1662
1663 filename = xmlBuildURI(sysid, base);
1664 if (filename != NULL) {
1665 xmlLoadCatalog((const char *)filename);
1666 xmlFree(filename);
1667 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001668 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001669 /*
1670 * drop anything else we won't handle it
1671 */
1672 if (name != NULL)
1673 xmlFree(name);
1674 if (sysid != NULL)
1675 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001676 }
1677 }
1678 if (base != NULL)
1679 xmlFree(base);
1680 if (cur == NULL)
1681 return(-1);
1682 return(0);
1683}
1684
Daniel Veillardcda96922001-08-21 10:56:31 +00001685/**
1686 * xmlCatalogGetSGMLPublic:
1687 * @catal: an SGML catalog hash
1688 * @pubId: the public ID string
1689 *
1690 * Try to lookup the system ID associated to a public ID
1691 *
1692 * Returns the system ID if found or NULL otherwise.
1693 */
1694static const xmlChar *
1695xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
1696 xmlCatalogEntryPtr entry;
1697
1698 if (catal == NULL)
1699 return(NULL);
1700
1701 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
1702 if (entry == NULL)
1703 return(NULL);
1704 if (entry->type == SGML_CATA_PUBLIC)
1705 return(entry->value);
1706 return(NULL);
1707}
1708
1709/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001710 * xmlCatalogGetSGMLSystem:
1711 * @catal: an SGML catalog hash
1712 * @sysId: the public ID string
1713 *
1714 * Try to lookup the catalog local reference for a system ID
1715 *
1716 * Returns the system ID if found or NULL otherwise.
1717 */
1718static const xmlChar *
1719xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
1720 xmlCatalogEntryPtr entry;
1721
1722 if (catal == NULL)
1723 return(NULL);
1724
1725 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
1726 if (entry == NULL)
1727 return(NULL);
1728 if (entry->type == SGML_CATA_SYSTEM)
1729 return(entry->value);
1730 return(NULL);
1731}
1732
1733/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001734 * xmlCatalogSGMLResolve:
1735 * @pubId: the public ID string
1736 * @sysId: the system ID string
1737 *
1738 * Do a complete resolution lookup of an External Identifier
1739 *
1740 * Returns the URI of the resource or NULL if not found
1741 */
1742static const xmlChar *
1743xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00001744 const xmlChar *ret = NULL;
1745
1746 if (xmlDefaultCatalog == NULL)
1747 return(NULL);
1748
1749 if (pubID != NULL)
1750 ret = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
1751 if (ret != NULL)
1752 return(ret);
1753 if (sysID != NULL)
1754 ret = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00001755 return(NULL);
1756}
1757
Daniel Veillarda7374592001-05-10 14:17:55 +00001758/************************************************************************
1759 * *
1760 * Public interfaces *
1761 * *
1762 ************************************************************************/
1763
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001764/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001765 * xmlInitializeCatalog:
1766 *
1767 * Do the catalog initialization.
1768 * TODO: this function is not thread safe, catalog initialization should
1769 * preferably be done once at startup
1770 */
1771void
1772xmlInitializeCatalog(void) {
1773 const char *catalogs;
1774
1775 if (xmlCatalogInitialized != 0)
1776 return;
1777
1778 if (getenv("XML_DEBUG_CATALOG"))
1779 xmlDebugCatalogs = 1;
1780 if ((xmlDefaultXMLCatalogList == NULL) && (xmlDefaultCatalog == NULL)) {
1781 catalogs = getenv("XML_CATALOG_FILES");
1782 if (catalogs == NULL)
1783 catalogs = XML_DEFAULT_CATALOG;
1784 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
1785 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
1786 }
1787
1788 xmlCatalogInitialized = 1;
1789}
1790
1791/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001792 * xmlLoadCatalog:
1793 * @filename: a file path
1794 *
Daniel Veillard81418e32001-05-22 15:08:55 +00001795 * Load the catalog and makes its definitions effective for the default
1796 * external entity loader. It will recuse in CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001797 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001798 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00001799 *
1800 * Returns 0 in case of success -1 in case of error
1801 */
1802int
1803xmlLoadCatalog(const char *filename) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001804 int fd, len, ret, i;
Daniel Veillarda7374592001-05-10 14:17:55 +00001805 struct stat info;
1806 xmlChar *content;
1807
1808 if (filename == NULL)
1809 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001810
Daniel Veillarda7374592001-05-10 14:17:55 +00001811 if (xmlDefaultCatalog == NULL)
1812 xmlDefaultCatalog = xmlHashCreate(20);
1813 if (xmlDefaultCatalog == NULL)
1814 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001815
1816 /*
1817 * Need to be done after ...
1818 */
1819 if (!xmlCatalogInitialized)
1820 xmlInitializeCatalog();
1821
1822#ifdef HAVE_STAT
Daniel Veillarda7374592001-05-10 14:17:55 +00001823 if (stat(filename, &info) < 0)
1824 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001825#endif
Daniel Veillarda7374592001-05-10 14:17:55 +00001826
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001827 /*
1828 * Prevent loops
1829 */
1830 for (i = 0;i < catalNr;i++) {
Daniel Veillard81418e32001-05-22 15:08:55 +00001831 if (xmlStrEqual((const xmlChar *)catalTab[i],
1832 (const xmlChar *)filename)) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001833 xmlGenericError(xmlGenericErrorContext,
1834 "xmlLoadCatalog: %s seems to induce a loop\n",
1835 filename);
1836 return(-1);
1837 }
1838 }
1839 if (catalNr >= catalMax) {
1840 xmlGenericError(xmlGenericErrorContext,
1841 "xmlLoadCatalog: %s catalog list too deep\n",
1842 filename);
1843 return(-1);
1844 }
1845 catalTab[catalNr++] = filename;
1846
1847 if ((fd = open(filename, O_RDONLY)) < 0) {
1848 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001849 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001850 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001851
1852 content = xmlMalloc(info.st_size + 10);
1853 if (content == NULL) {
1854 xmlGenericError(xmlGenericErrorContext,
1855 "realloc of %d byte failed\n", info.st_size + 10);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001856 catalNr--;
1857 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00001858 }
1859 len = read(fd, content, info.st_size);
1860 if (len < 0) {
1861 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001862 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001863 return(-1);
1864 }
1865 content[len] = 0;
1866 close(fd);
1867
Daniel Veillard344cee72001-08-20 00:08:40 +00001868 if ((content[0] == ' ') || (content[0] == '-') ||
1869 ((content[0] >= 'A') && (content[0] <= 'Z')) ||
1870 ((content[0] >= 'a') && (content[0] <= 'z')))
Daniel Veillardcda96922001-08-21 10:56:31 +00001871 ret = xmlParseSGMLCatalog(content, filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001872 else {
1873 xmlCatalogEntryPtr catal, tmp;
1874 /* TODO: allow to switch the default preference */
1875 catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
1876 if (catal != NULL) {
1877 if (xmlDefaultXMLCatalogList == NULL)
1878 xmlDefaultXMLCatalogList = catal;
1879 else {
1880 tmp = xmlDefaultXMLCatalogList;
1881 while (tmp->next != NULL)
1882 tmp = tmp->next;
1883 tmp->next = catal;
1884 }
1885 ret = 0;
1886 } else
1887 ret = -1;
1888 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001889 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001890 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001891 return(ret);
1892}
1893
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001894/**
Daniel Veillard81418e32001-05-22 15:08:55 +00001895 * xmlLoadCatalogs:
1896 * @paths: a list of file path separated by ':' or spaces
1897 *
1898 * Load the catalogs and makes their definitions effective for the default
1899 * external entity loader.
1900 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001901 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00001902 */
1903void
1904xmlLoadCatalogs(const char *pathss) {
1905 const char *cur;
1906 const char *paths;
1907 xmlChar *path;
1908
1909 cur = pathss;
1910 while ((cur != NULL) && (*cur != 0)) {
1911 while (IS_BLANK(*cur)) cur++;
1912 if (*cur != 0) {
1913 paths = cur;
1914 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
1915 cur++;
1916 path = xmlStrndup((const xmlChar *)paths, cur - paths);
1917 if (path != NULL) {
1918 xmlLoadCatalog((const char *) path);
1919 xmlFree(path);
1920 }
1921 }
1922 while (*cur == ':')
1923 cur++;
1924 }
1925}
1926
Daniel Veillarda7374592001-05-10 14:17:55 +00001927/**
1928 * xmlCatalogCleanup:
1929 *
1930 * Free up all the memory associated with catalogs
1931 */
1932void
1933xmlCatalogCleanup(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001934 if (xmlDebugCatalogs)
1935 xmlGenericError(xmlGenericErrorContext,
1936 "Catalogs cleanup\n");
Daniel Veillardcda96922001-08-21 10:56:31 +00001937 if (xmlDefaultXMLCatalogList != NULL)
1938 xmlFreeCatalogEntryList(xmlDefaultXMLCatalogList);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001939 xmlDefaultXMLCatalogList = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001940 if (xmlDefaultCatalog != NULL)
1941 xmlHashFree(xmlDefaultCatalog,
1942 (xmlHashDeallocator) xmlFreeCatalogEntry);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001943 xmlDebugCatalogs = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00001944 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001945 xmlCatalogInitialized = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00001946}
1947
1948/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001949 * xmlCatalogGetSystem:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001950 * @pubId: the public ID string
Daniel Veillarda7374592001-05-10 14:17:55 +00001951 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001952 * Try to lookup the system ID associated to a public ID
1953 * DEPRECATED, use xmlCatalogResolveSystem()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001954 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001955 * Returns the system ID if found or NULL otherwise.
Daniel Veillarda7374592001-05-10 14:17:55 +00001956 */
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001957const xmlChar *
1958xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001959 xmlChar *ret;
1960 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001961
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001962 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001963 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001964
1965 if (!xmlCatalogInitialized)
1966 xmlInitializeCatalog();
1967
1968 /*
1969 * Check first the XML catalogs
1970 */
1971 if (xmlDefaultXMLCatalogList != NULL) {
1972 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
1973 if (ret != NULL) {
1974 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
1975 result[sizeof(result) - 1] = 0;
1976 return(result);
1977 }
1978 }
1979
1980 if (xmlDefaultCatalog != NULL)
1981 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID));
1982 return(NULL);
1983}
1984
1985/**
1986 * xmlCatalogResolveSystem:
1987 * @sysId: the public ID string
1988 *
1989 * Try to lookup the catalog resource for a system ID
1990 *
1991 * Returns the system ID if found or NULL otherwise, the value returned
1992 * must be freed by the caller.
1993 */
1994xmlChar *
1995xmlCatalogResolveSystem(const xmlChar *sysID) {
1996 xmlCatalogEntryPtr catal;
1997 xmlChar *ret;
1998 const xmlChar *sgml;
1999
2000 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002001 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002002
2003 if (!xmlCatalogInitialized)
2004 xmlInitializeCatalog();
2005
2006 /*
2007 * Check first the XML catalogs
2008 */
2009 catal = xmlDefaultXMLCatalogList;
2010 if (catal != NULL) {
2011 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
2012 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2013 return(ret);
2014 }
2015
2016 if (xmlDefaultCatalog != NULL) {
2017 sgml = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
2018 if (sgml != NULL)
2019 return(xmlStrdup(sgml));
2020 }
Daniel Veillard344cee72001-08-20 00:08:40 +00002021 return(NULL);
2022}
2023
2024/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002025 * xmlCatalogGetPublic:
2026 * @pubId: the public ID string
2027 *
2028 * Try to lookup the system ID associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002029 * DEPRECATED, use xmlCatalogResolvePublic()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002030 *
2031 * Returns the system ID if found or NULL otherwise.
2032 */
2033const xmlChar *
2034xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002035 xmlChar *ret;
2036 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002037
Daniel Veillard344cee72001-08-20 00:08:40 +00002038 if (pubID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002039 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00002040
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002041 if (!xmlCatalogInitialized)
2042 xmlInitializeCatalog();
2043
2044 /*
2045 * Check first the XML catalogs
2046 */
2047 if (xmlDefaultXMLCatalogList != NULL) {
2048 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2049 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
2050 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
2051 result[sizeof(result) - 1] = 0;
2052 return(result);
2053 }
2054 }
2055
2056 if (xmlDefaultCatalog != NULL)
2057 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
2058 return(NULL);
2059}
2060
2061/**
2062 * xmlCatalogResolvePublic:
2063 * @pubId: the public ID string
2064 *
2065 * Try to lookup the system ID associated to a public ID
2066 *
2067 * Returns the system ID if found or NULL otherwise, the value returned
2068 * must be freed by the caller.
2069 */
2070xmlChar *
2071xmlCatalogResolvePublic(const xmlChar *pubID) {
2072 xmlCatalogEntryPtr catal;
2073 xmlChar *ret;
2074 const xmlChar *sgml;
2075
2076 if (pubID == NULL)
2077 return(NULL);
2078
2079 if (!xmlCatalogInitialized)
2080 xmlInitializeCatalog();
2081
Daniel Veillard344cee72001-08-20 00:08:40 +00002082 /*
2083 * Check first the XML catalogs
2084 */
2085 catal = xmlDefaultXMLCatalogList;
2086 if (catal != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002087 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2088 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
Daniel Veillard344cee72001-08-20 00:08:40 +00002089 return(ret);
2090 }
2091
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002092 if (xmlDefaultCatalog != NULL) {
2093 sgml = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
2094 if (sgml != NULL)
2095 return(xmlStrdup(sgml));
2096 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002097 return(NULL);
2098}
Daniel Veillard344cee72001-08-20 00:08:40 +00002099
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002100/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002101 * xmlCatalogResolve:
2102 * @pubId: the public ID string
2103 * @sysId: the system ID string
2104 *
2105 * Do a complete resolution lookup of an External Identifier
2106 *
2107 * Returns the URI of the resource or NULL if not found, it must be freed
2108 * by the caller.
2109 */
2110xmlChar *
2111xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002112 if (!xmlCatalogInitialized)
2113 xmlInitializeCatalog();
2114
Daniel Veillardcda96922001-08-21 10:56:31 +00002115 if (xmlDefaultXMLCatalogList != NULL) {
2116 return(xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, sysID));
2117 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002118 const xmlChar *ret;
2119
2120 ret = xmlCatalogSGMLResolve(pubID, sysID);
2121 if (ret != NULL)
2122 return(xmlStrdup(ret));
Daniel Veillardcda96922001-08-21 10:56:31 +00002123 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002124 return(NULL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002125}
2126
2127/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002128 * xmlCatalogResolveURI:
2129 * @pubId: the URI
2130 *
2131 * Do a complete resolution lookup of an URI
2132 *
2133 * Returns the URI of the resource or NULL if not found, it must be freed
2134 * by the caller.
2135 */
2136xmlChar *
2137xmlCatalogResolveURI(const xmlChar *URI) {
2138 if (!xmlCatalogInitialized)
2139 xmlInitializeCatalog();
2140
2141 if (xmlDefaultXMLCatalogList != NULL) {
2142 return(xmlCatalogListXMLResolveURI(xmlDefaultXMLCatalogList, URI));
2143 } else {
2144 const xmlChar *ret;
2145
2146 ret = xmlCatalogSGMLResolve(NULL, URI);
2147 if (ret != NULL)
2148 return(xmlStrdup(ret));
2149 }
2150 return(NULL);
2151}
2152
2153/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002154 * xmlCatalogDump:
2155 * @out: the file.
2156 *
2157 * Free up all the memory associated with catalogs
2158 */
2159void
2160xmlCatalogDump(FILE *out) {
2161 if (out == NULL)
2162 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00002163
2164 if (xmlDefaultXMLCatalogList != NULL) {
2165 xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList);
2166 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002167 xmlHashScan(xmlDefaultCatalog,
2168 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00002169 }
2170}
2171
2172/**
2173 * xmlCatalogAdd:
2174 * @type: the type of record to add to the catalog
2175 * @orig: the system, public or prefix to match
2176 * @replace: the replacement value for the match
2177 *
2178 * Add an entry in the catalog, it may overwrite existing but
2179 * different entries.
2180 *
2181 * Returns 0 if successful, -1 otherwise
2182 */
2183int
2184xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
2185 int res = -1;
2186
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00002187 if ((xmlDefaultXMLCatalogList == NULL) &&
2188 (xmlStrEqual(type, BAD_CAST "catalog"))) {
2189 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2190 orig, xmlCatalogDefaultPrefer);
2191 return(0);
2192 }
2193
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002194 if (!xmlCatalogInitialized)
2195 xmlInitializeCatalog();
2196
Daniel Veillard344cee72001-08-20 00:08:40 +00002197 if (xmlDefaultXMLCatalogList != NULL) {
2198 res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
2199 } else if (xmlDefaultCatalog != NULL) {
2200 xmlCatalogEntryType typ;
2201
Daniel Veillardcda96922001-08-21 10:56:31 +00002202 typ = xmlGetSGMLCatalogEntryType(type);
Daniel Veillard344cee72001-08-20 00:08:40 +00002203 if (type != XML_CATA_NONE) {
2204 xmlCatalogEntryPtr entry;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002205 entry = xmlNewCatalogEntry(typ, orig, replace, XML_CATA_PREFER_NONE);
Daniel Veillard344cee72001-08-20 00:08:40 +00002206 res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
2207 }
2208 }
2209 return(res);
2210}
2211
2212/**
2213 * xmlCatalogRemove:
2214 * @value: the value to remove
2215 *
2216 * Remove an entry from the catalog
2217 *
2218 * Returns 0 if successful, -1 otherwise
2219 */
2220int
2221xmlCatalogRemove(const xmlChar *value) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002222 int res = -1;
2223
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002224 if (!xmlCatalogInitialized)
2225 xmlInitializeCatalog();
2226
Daniel Veillardcda96922001-08-21 10:56:31 +00002227 if (xmlDefaultXMLCatalogList != NULL) {
2228 res = xmlDelXMLCatalog(xmlDefaultXMLCatalogList, value);
2229 } else if (xmlDefaultCatalog != NULL) {
2230 TODO
2231 }
2232 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00002233}
2234
2235/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002236 * xmlCatalogGetDefaults:
2237 *
2238 * Used to get the user preference w.r.t. to what catalogs should
2239 * be accepted
2240 *
2241 * Returns the current xmlCatalogAllow value
2242 */
2243xmlCatalogAllow
2244xmlCatalogGetDefaults(void) {
2245 return(xmlCatalogDefaultAllow);
2246}
2247
2248/**
2249 * xmlCatalogSetDefaults:
2250 *
2251 * Used to set the user preference w.r.t. to what catalogs should
2252 * be accepted
2253 */
2254void
2255xmlCatalogSetDefaults(xmlCatalogAllow allow) {
2256 if (!xmlCatalogInitialized)
2257 xmlInitializeCatalog();
2258 if (xmlDebugCatalogs) {
2259 switch (allow) {
2260 case XML_CATA_ALLOW_NONE:
2261 xmlGenericError(xmlGenericErrorContext,
2262 "Disabling catalog usage\n");
2263 break;
2264 case XML_CATA_ALLOW_GLOBAL:
2265 xmlGenericError(xmlGenericErrorContext,
2266 "Allowing only global catalogs\n");
2267 break;
2268 case XML_CATA_ALLOW_DOCUMENT:
2269 xmlGenericError(xmlGenericErrorContext,
2270 "Allowing only catalogs from the document\n");
2271 break;
2272 case XML_CATA_ALLOW_ALL:
2273 xmlGenericError(xmlGenericErrorContext,
2274 "Allowing all catalogs\n");
2275 break;
2276 }
2277 }
2278 xmlCatalogDefaultAllow = allow;
2279}
2280
2281/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002282 * xmlCatalogSetDefaultPrefer:
2283 * @prefer: the default preference for delegation
2284 *
2285 * Allows to set the preference between public and system for deletion
2286 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002287 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002288 *
2289 * Returns the previous value of the default preference for delegation
2290 */
2291xmlCatalogPrefer
2292xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
2293 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
2294
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002295 if (!xmlCatalogInitialized)
2296 xmlInitializeCatalog();
2297 if (prefer == XML_CATA_PREFER_NONE)
2298 return(ret);
2299
2300 if (xmlDebugCatalogs) {
2301 switch (prefer) {
2302 case XML_CATA_PREFER_PUBLIC:
2303 xmlGenericError(xmlGenericErrorContext,
2304 "Setting catalog preference to PUBLIC\n");
2305 break;
2306 case XML_CATA_PREFER_SYSTEM:
2307 xmlGenericError(xmlGenericErrorContext,
2308 "Setting catalog preference to SYSTEM\n");
2309 break;
2310 case XML_CATA_PREFER_NONE:
2311 break;
2312 }
2313 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002314 xmlCatalogDefaultPrefer = prefer;
2315 return(ret);
2316}
2317
2318/**
Daniel Veillard344cee72001-08-20 00:08:40 +00002319 * xmlCatalogSetDebug:
2320 * @level: the debug level of catalogs required
2321 *
2322 * Used to set the debug level for catalog operation, 0 disable
2323 * debugging, 1 enable it
2324 *
2325 * Returns the previous value of the catalog debugging level
2326 */
2327int
2328xmlCatalogSetDebug(int level) {
2329 int ret = xmlDebugCatalogs;
2330
2331 if (level <= 0)
2332 xmlDebugCatalogs = 0;
2333 else
2334 xmlDebugCatalogs = level;
2335 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002336}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002337
2338/**
2339 * xmlCatalogFreeLocal:
2340 * @catalogs: a document's list of catalogs
2341 *
2342 * Free up the memory associated to the catalog list
2343 */
2344void
2345xmlCatalogFreeLocal(void *catalogs) {
2346 xmlCatalogEntryPtr catal;
2347
2348 catal = (xmlCatalogEntryPtr) catalogs;
2349 if (catal != NULL)
2350 xmlFreeCatalogEntryList(catal);
2351}
2352
2353
2354/**
2355 * xmlCatalogAddLocal:
2356 * @catalogs: a document's list of catalogs
2357 * @URL: the URL to a new local catalog
2358 *
2359 * Add the new entry to the catalog list
2360 *
2361 * Returns the updated list
2362 */
2363void *
2364xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
2365 xmlCatalogEntryPtr catal, add;
2366
2367 if (!xmlCatalogInitialized)
2368 xmlInitializeCatalog();
2369 if (URL == NULL)
2370 return(catalogs);
2371
2372 if (xmlDebugCatalogs)
2373 xmlGenericError(xmlGenericErrorContext,
2374 "Adding document catalog %s\n", URL);
2375
2376 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
2377 xmlCatalogDefaultPrefer);
2378 if (add == NULL)
2379 return(catalogs);
2380
2381 catal = (xmlCatalogEntryPtr) catalogs;
2382 if (catal == NULL)
2383 return((void *) add);
2384
2385 while (catal->next != NULL)
2386 catal = catal->next;
2387 catal->next = add;
2388 return(catalogs);
2389}
2390
2391/**
2392 * xmlCatalogLocalResolve:
2393 * @catalogs: a document's list of catalogs
2394 * @pubId: the public ID string
2395 * @sysId: the system ID string
2396 *
2397 * Do a complete resolution lookup of an External Identifier using a
2398 * document's private catalog list
2399 *
2400 * Returns the URI of the resource or NULL if not found, it must be freed
2401 * by the caller.
2402 */
2403xmlChar *
2404xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
2405 const xmlChar *sysID) {
2406 xmlCatalogEntryPtr catal;
2407
2408 if (!xmlCatalogInitialized)
2409 xmlInitializeCatalog();
2410 catal = (xmlCatalogEntryPtr) catalogs;
2411 if (catal == NULL)
2412 return(NULL);
2413 return(xmlCatalogListXMLResolve(catal, pubID, sysID));
2414}
2415
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002416/**
2417 * xmlCatalogLocalResolveURI:
2418 * @catalogs: a document's list of catalogs
2419 * @pubId: the URI
2420 *
2421 * Do a complete resolution lookup of an URI using a
2422 * document's private catalog list
2423 *
2424 * Returns the URI of the resource or NULL if not found, it must be freed
2425 * by the caller.
2426 */
2427xmlChar *
2428xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
2429 xmlCatalogEntryPtr catal;
2430
2431 if (!xmlCatalogInitialized)
2432 xmlInitializeCatalog();
2433 catal = (xmlCatalogEntryPtr) catalogs;
2434 if (catal == NULL)
2435 return(NULL);
2436 return(xmlCatalogListXMLResolveURI(catal, URI));
2437}
2438
Daniel Veillarda7374592001-05-10 14:17:55 +00002439#endif /* LIBXML_CATALOG_ENABLED */