blob: d645d887e3f057fb89459271101baa0d44c2bdf9 [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 Veillard344cee72001-08-20 00:08:40 +000049
Daniel Veillarda7374592001-05-10 14:17:55 +000050/************************************************************************
51 * *
52 * Types, all private *
53 * *
54 ************************************************************************/
55
56typedef enum {
Daniel Veillard344cee72001-08-20 00:08:40 +000057 XML_CATA_PREFER_PUBLIC = 1,
58 XML_CATA_PREFER_SYSTEM
59} xmlCatalogPrefer;
60
61typedef enum {
Daniel Veillarda7374592001-05-10 14:17:55 +000062 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000063 XML_CATA_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000064 XML_CATA_NEXT_CATALOG,
65 XML_CATA_PUBLIC,
66 XML_CATA_SYSTEM,
67 XML_CATA_REWRITE_SYSTEM,
68 XML_CATA_DELEGATE_PUBLIC,
69 XML_CATA_DELEGATE_SYSTEM,
70 XML_CATA_URI,
71 XML_CATA_REWRITE_URI,
72 XML_CATA_DELEGATE_URI,
73 SGML_CATA_SYSTEM,
74 SGML_CATA_PUBLIC,
75 SGML_CATA_ENTITY,
76 SGML_CATA_PENTITY,
77 SGML_CATA_DOCTYPE,
78 SGML_CATA_LINKTYPE,
79 SGML_CATA_NOTATION,
80 SGML_CATA_DELEGATE,
81 SGML_CATA_BASE,
82 SGML_CATA_CATALOG,
83 SGML_CATA_DOCUMENT,
84 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000085} xmlCatalogEntryType;
86
87typedef struct _xmlCatalogEntry xmlCatalogEntry;
88typedef xmlCatalogEntry *xmlCatalogEntryPtr;
89struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +000090 struct _xmlCatalogEntry *next;
91 struct _xmlCatalogEntry *parent;
92 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +000093 xmlCatalogEntryType type;
94 xmlChar *name;
95 xmlChar *value;
Daniel Veillardcda96922001-08-21 10:56:31 +000096 /* TODO : 1234 xmlCatalogPrefer prefer */
Daniel Veillarda7374592001-05-10 14:17:55 +000097};
98
99static xmlHashTablePtr xmlDefaultCatalog;
Daniel Veillard344cee72001-08-20 00:08:40 +0000100static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000101
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000102/* Catalog stack */
Daniel Veillard81418e32001-05-22 15:08:55 +0000103static const char * catalTab[10]; /* stack of catals */
104static int catalNr = 0; /* Number of current catal streams */
105static int catalMax = 10; /* Max number of catal streams */
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000106
Daniel Veillard344cee72001-08-20 00:08:40 +0000107static int xmlDebugCatalogs = 0; /* used for debugging */
108
Daniel Veillarda7374592001-05-10 14:17:55 +0000109/************************************************************************
110 * *
111 * alloc or dealloc *
112 * *
113 ************************************************************************/
114
115static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000116xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
117 const xmlChar *value) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000118 xmlCatalogEntryPtr ret;
119
120 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
121 if (ret == NULL) {
122 xmlGenericError(xmlGenericErrorContext,
123 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
124 return(NULL);
125 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000126 ret->next = NULL;
127 ret->parent = NULL;
128 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000129 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000130 if (name != NULL)
131 ret->name = xmlStrdup(name);
132 else
133 ret->name = NULL;
134 if (value != NULL)
135 ret->value = xmlStrdup(value);
136 else
137 ret->value = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000138 return(ret);
139}
140
141static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000142xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
143
144static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000145xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
146 if (ret == NULL)
147 return;
Daniel Veillard344cee72001-08-20 00:08:40 +0000148 if (ret->children != NULL)
149 xmlFreeCatalogEntryList(ret->children);
Daniel Veillarda7374592001-05-10 14:17:55 +0000150 if (ret->name != NULL)
151 xmlFree(ret->name);
152 if (ret->value != NULL)
153 xmlFree(ret->value);
154 xmlFree(ret);
155}
156
Daniel Veillard344cee72001-08-20 00:08:40 +0000157static void
158xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
159 xmlCatalogEntryPtr next;
160
161 while (ret != NULL) {
162 next = ret->next;
163 xmlFreeCatalogEntry(ret);
164 ret = next;
165 }
166}
167
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000168/**
169 * xmlCatalogDumpEntry:
170 * @entry: the
171 * @out: the file.
172 *
173 * Free up all the memory associated with catalogs
174 */
175static void
176xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
177 if ((entry == NULL) || (out == NULL))
178 return;
179 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000180 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000181 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000182 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000183 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000184 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000185 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000186 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000187 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000188 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000189 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000190 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000191 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000192 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000193 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000194 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000195 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000196 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000197 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000198 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000199 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000200 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000201 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000202 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000203 fprintf(out, "SGMLDECL "); break;
204 default:
205 return;
206 }
207 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000208 case SGML_CATA_ENTITY:
209 case SGML_CATA_PENTITY:
210 case SGML_CATA_DOCTYPE:
211 case SGML_CATA_LINKTYPE:
212 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000213 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000214 case SGML_CATA_PUBLIC:
215 case SGML_CATA_SYSTEM:
216 case SGML_CATA_SGMLDECL:
217 case SGML_CATA_DOCUMENT:
218 case SGML_CATA_CATALOG:
219 case SGML_CATA_BASE:
220 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000221 fprintf(out, "\"%s\"", entry->name); break;
222 default:
223 break;
224 }
225 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000226 case SGML_CATA_ENTITY:
227 case SGML_CATA_PENTITY:
228 case SGML_CATA_DOCTYPE:
229 case SGML_CATA_LINKTYPE:
230 case SGML_CATA_NOTATION:
231 case SGML_CATA_PUBLIC:
232 case SGML_CATA_SYSTEM:
233 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000234 fprintf(out, " \"%s\"", entry->value); break;
235 default:
236 break;
237 }
238 fprintf(out, "\n");
239}
240
Daniel Veillarda7374592001-05-10 14:17:55 +0000241/************************************************************************
242 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000243 * The XML Catalog parser *
244 * *
245 ************************************************************************/
246
247static xmlCatalogEntryPtr
248xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
249
250static xmlCatalogEntryPtr
251xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
252 const char *file);
253static void
254xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
255 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000256static xmlChar *
257xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
258 const xmlChar *sysID);
Daniel Veillard344cee72001-08-20 00:08:40 +0000259
260static xmlCatalogEntryType
261xmlGetXMLCatalogEntryType(const xmlChar *name) {
262 xmlCatalogEntryType type = XML_CATA_NONE;
263 if (xmlStrEqual(name, (const xmlChar *) "system"))
264 type = XML_CATA_SYSTEM;
265 else if (xmlStrEqual(name, (const xmlChar *) "public"))
266 type = XML_CATA_PUBLIC;
267 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
268 type = XML_CATA_REWRITE_SYSTEM;
269 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
270 type = XML_CATA_DELEGATE_PUBLIC;
271 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
272 type = XML_CATA_DELEGATE_SYSTEM;
273 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
274 type = XML_CATA_URI;
275 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
276 type = XML_CATA_REWRITE_URI;
277 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
278 type = XML_CATA_DELEGATE_URI;
279 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
280 type = XML_CATA_NEXT_CATALOG;
281 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
282 type = XML_CATA_CATALOG;
283 return(type);
284}
285
286static xmlCatalogEntryPtr
287xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
288 const xmlChar *name, const xmlChar *attrName,
289 const xmlChar *uriAttrName) {
290 int ok = 1;
291 xmlChar *uriValue;
292 xmlChar *nameValue = NULL;
293 xmlChar *base = NULL;
294 xmlChar *URL = NULL;
295 xmlCatalogEntryPtr ret = NULL;
296
297 if (attrName != NULL) {
298 nameValue = xmlGetProp(cur, attrName);
299 if (nameValue == NULL) {
300 xmlGenericError(xmlGenericErrorContext,
301 "%s entry lacks '%s'\n", name, attrName);
302 ok = 0;
303 }
304 }
305 uriValue = xmlGetProp(cur, uriAttrName);
306 if (uriValue == NULL) {
307 xmlGenericError(xmlGenericErrorContext,
308 "%s entry lacks '%s'\n", name, uriAttrName);
309 ok = 0;
310 }
311 if (!ok) {
312 if (nameValue != NULL)
313 xmlFree(nameValue);
314 if (uriValue != NULL)
315 xmlFree(uriValue);
316 return(NULL);
317 }
318
319 base = xmlNodeGetBase(cur->doc, cur);
320 URL = xmlBuildURI(uriValue, base);
321 if (URL != NULL) {
322 if (xmlDebugCatalogs) {
323 if (nameValue != NULL)
324 printf("Found %s: '%s' '%s'\n", name, nameValue, URL);
325 else
326 printf("Found %s: '%s'\n", name, URL);
327 }
328 ret = xmlNewCatalogEntry(type, nameValue, URL);
329 } else {
330 xmlGenericError(xmlGenericErrorContext,
331 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
332 }
333 if (nameValue != NULL)
334 xmlFree(nameValue);
335 if (uriValue != NULL)
336 xmlFree(uriValue);
337 if (base != NULL)
338 xmlFree(base);
339 if (URL != NULL)
340 xmlFree(URL);
341 return(ret);
342}
343
344static void
345xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
346 xmlCatalogEntryPtr parent)
347{
348 xmlChar *uri = NULL;
349 xmlChar *URL = NULL;
350 xmlChar *base = NULL;
351 xmlCatalogEntryPtr entry = NULL;
352
353 if (cur == NULL)
354 return;
355 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
356 xmlChar *prop;
357
358 prop = xmlGetProp(cur, BAD_CAST "prefer");
359 if (prop != NULL) {
360 if (xmlStrEqual(prop, BAD_CAST "system")) {
361 prefer = XML_CATA_PREFER_SYSTEM;
362 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
363 prefer = XML_CATA_PREFER_PUBLIC;
364 } else {
365 xmlGenericError(xmlGenericErrorContext,
366 "Invalid value for prefer: '%s'\n", prop);
367 }
368 xmlFree(prop);
369 }
370 /*
371 * Recurse to propagate prefer to the subtree
372 * (xml:base handling is automated)
373 */
374 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
375 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
376 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
377 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri");
378 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
379 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
380 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri");
381 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
382 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
383 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
384 BAD_CAST "rewritePrefix");
385 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
386 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
387 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
388 BAD_CAST "catalog");
389 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
390 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
391 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
392 BAD_CAST "catalog");
393 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
394 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
395 BAD_CAST "uri", BAD_CAST "name",
396 BAD_CAST "uri");
397 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
398 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
399 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
400 BAD_CAST "rewritePrefix");
401 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
402 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
403 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
404 BAD_CAST "catalog");
405 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
406 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
407 BAD_CAST "nextCatalog", NULL,
408 BAD_CAST "catalog");
409 }
410 if ((entry != NULL) && (parent != NULL)) {
411 entry->parent = parent;
412 if (parent->children == NULL)
413 parent->children = entry;
414 else {
415 xmlCatalogEntryPtr prev;
416
417 prev = parent->children;
418 while (prev->next != NULL)
419 prev = prev->next;
420 prev->next = entry;
421 }
422 }
423 if (base != NULL)
424 xmlFree(base);
425 if (uri != NULL)
426 xmlFree(uri);
427 if (URL != NULL)
428 xmlFree(URL);
429}
430
431static void
432xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
433 xmlCatalogEntryPtr parent) {
434 while (cur != NULL) {
435 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
436 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
437 xmlParseXMLCatalogNode(cur, prefer, parent);
438 }
439 cur = cur->next;
440 }
441 /* TODO: sort the list according to REWRITE lengths and prefer value */
442}
443
444static xmlCatalogEntryPtr
445xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
446 const char *file) {
447 xmlDocPtr doc;
448 xmlNodePtr cur;
449 xmlChar *prop;
450 xmlCatalogEntryPtr parent = NULL;
451
452 if ((value == NULL) || (file == NULL))
453 return(NULL);
454
455 doc = xmlParseDoc((xmlChar *) value);
456 if (doc == NULL)
457 return(NULL);
458 doc->URL = xmlStrdup((const xmlChar *) file);
459
460 cur = xmlDocGetRootElement(doc);
461 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
462 (cur->ns != NULL) && (cur->ns->href != NULL) &&
463 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
464
465 parent = xmlNewCatalogEntry(XML_CATA_CATALOG,
466 (const xmlChar *)file, NULL);
467 if (parent == NULL) {
468 xmlFreeDoc(doc);
469 return(NULL);
470 }
471
472 prop = xmlGetProp(cur, BAD_CAST "prefer");
473 if (prop != NULL) {
474 if (xmlStrEqual(prop, BAD_CAST "system")) {
475 prefer = XML_CATA_PREFER_SYSTEM;
476 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
477 prefer = XML_CATA_PREFER_PUBLIC;
478 } else {
479 xmlGenericError(xmlGenericErrorContext,
480 "Invalid value for prefer: '%s'\n",
481 prop);
482 }
483 xmlFree(prop);
484 }
485 cur = cur->children;
486 xmlParseXMLCatalogNodeList(cur, prefer, parent);
487 } else {
488 xmlGenericError(xmlGenericErrorContext,
489 "File %s is not an XML Catalog\n", file);
490 xmlFreeDoc(doc);
491 return(NULL);
492 }
493 xmlFreeDoc(doc);
494 return(parent);
495}
496
497static xmlCatalogEntryPtr
498xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
499 xmlDocPtr doc;
500 xmlNodePtr cur;
501 xmlChar *prop;
502 xmlCatalogEntryPtr parent = NULL;
503
504 if (filename == NULL)
505 return(NULL);
506
507 doc = xmlParseFile((const char *) filename);
508 if (doc == NULL)
509 return(NULL);
510
511 cur = xmlDocGetRootElement(doc);
512 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
513 (cur->ns != NULL) && (cur->ns->href != NULL) &&
514 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
515
516 parent = xmlNewCatalogEntry(XML_CATA_CATALOG,
517 (const xmlChar *)filename, NULL);
518 if (parent == NULL) {
519 xmlFreeDoc(doc);
520 return(NULL);
521 }
522
523 prop = xmlGetProp(cur, BAD_CAST "prefer");
524 if (prop != NULL) {
525 if (xmlStrEqual(prop, BAD_CAST "system")) {
526 prefer = XML_CATA_PREFER_SYSTEM;
527 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
528 prefer = XML_CATA_PREFER_PUBLIC;
529 } else {
530 xmlGenericError(xmlGenericErrorContext,
531 "Invalid value for prefer: '%s'\n",
532 prop);
533 }
534 xmlFree(prop);
535 }
536 cur = cur->children;
537 xmlParseXMLCatalogNodeList(cur, prefer, parent);
538 } else {
539 xmlGenericError(xmlGenericErrorContext,
540 "File %s is not an XML Catalog\n", filename);
541 xmlFreeDoc(doc);
542 return(NULL);
543 }
544 xmlFreeDoc(doc);
545 return(parent);
546}
547
Daniel Veillardcda96922001-08-21 10:56:31 +0000548/**
549 * xmlFetchXMLCatalogFile:
550 * @catal: an existing but incomplete catalog entry
551 *
552 * Fetch and parse the subcatalog referenced by an entry
553 * It tries to be thread safe but by lack of an atomic test and
554 * set there is a risk of loosing memory.
555 *
556 * Returns 0 in case of success, -1 otherwise
557 */
558static int
559xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
560 xmlCatalogEntryPtr children;
561
562 if (catal == NULL)
563 return(-1);
564 if (catal->value == NULL)
565 return(-1);
566 if (catal->children != NULL)
567 return(-1);
568
569 /*
570 * Fetch and parse
571 */
572 /* TODO : 1234 s/XML_CATA_PREFER_PUBLIC/catal->prefer */
573 children = xmlParseXMLCatalogFile(XML_CATA_PREFER_PUBLIC, catal->value);
574 if (children == NULL)
575 return(-1);
576
577 /*
578 * Where a real test and set would be needed !
579 */
580 if (catal->children == NULL) {
581 catal->children = children;
582 } else {
583 /*
584 * Another thread filled it before us
585 */
586 xmlFreeCatalogEntryList(children);
587 }
588 return(0);
589}
590
Daniel Veillard344cee72001-08-20 00:08:40 +0000591static int
592xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
593 int ret;
594 xmlDocPtr doc;
595 xmlNsPtr ns;
596 xmlDtdPtr dtd;
597 xmlNodePtr node, catalog;
598 xmlOutputBufferPtr buf;
599 xmlCatalogEntryPtr cur;
600
601 /*
602 * Rebuild a catalog
603 */
604 doc = xmlNewDoc(NULL);
605 if (doc == NULL)
606 return(-1);
607 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
608 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
609BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
610
611 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
612
613 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
614 if (ns == NULL) {
615 xmlFreeDoc(doc);
616 return(-1);
617 }
618 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
619 if (catalog == NULL) {
620 xmlFreeNs(ns);
621 xmlFreeDoc(doc);
622 return(-1);
623 }
624 catalog->nsDef = ns;
625 xmlAddChild((xmlNodePtr) doc, catalog);
626
627 /*
628 * add all the catalog entries
629 */
630 cur = catal;
631 while (cur != NULL) {
632 switch (cur->type) {
633 case XML_CATA_CATALOG:
634 if (cur == catal) {
635 cur = cur->children;
636 continue;
637 }
638 break;
639 case XML_CATA_NEXT_CATALOG:
640 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
641 xmlSetProp(node, BAD_CAST "catalog", cur->value);
642 xmlAddChild(catalog, node);
643 break;
644 case XML_CATA_NONE:
645 break;
646 case XML_CATA_PUBLIC:
647 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
648 xmlSetProp(node, BAD_CAST "publicId", cur->name);
649 xmlSetProp(node, BAD_CAST "uri", cur->value);
650 xmlAddChild(catalog, node);
651 break;
652 case XML_CATA_SYSTEM:
653 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
654 xmlSetProp(node, BAD_CAST "systemId", cur->name);
655 xmlSetProp(node, BAD_CAST "uri", cur->value);
656 xmlAddChild(catalog, node);
657 break;
658 case XML_CATA_REWRITE_SYSTEM:
659 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
660 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
661 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
662 xmlAddChild(catalog, node);
663 break;
664 case XML_CATA_DELEGATE_PUBLIC:
665 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
666 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
667 xmlSetProp(node, BAD_CAST "catalog", cur->value);
668 xmlAddChild(catalog, node);
669 break;
670 case XML_CATA_DELEGATE_SYSTEM:
671 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
672 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
673 xmlSetProp(node, BAD_CAST "catalog", cur->value);
674 xmlAddChild(catalog, node);
675 break;
676 case XML_CATA_URI:
677 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
678 xmlSetProp(node, BAD_CAST "name", cur->name);
679 xmlSetProp(node, BAD_CAST "uri", cur->value);
680 xmlAddChild(catalog, node);
681 break;
682 case XML_CATA_REWRITE_URI:
683 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
684 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
685 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
686 xmlAddChild(catalog, node);
687 break;
688 case XML_CATA_DELEGATE_URI:
689 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
690 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
691 xmlSetProp(node, BAD_CAST "catalog", cur->value);
692 xmlAddChild(catalog, node);
693 break;
694 case SGML_CATA_SYSTEM:
695 case SGML_CATA_PUBLIC:
696 case SGML_CATA_ENTITY:
697 case SGML_CATA_PENTITY:
698 case SGML_CATA_DOCTYPE:
699 case SGML_CATA_LINKTYPE:
700 case SGML_CATA_NOTATION:
701 case SGML_CATA_DELEGATE:
702 case SGML_CATA_BASE:
703 case SGML_CATA_CATALOG:
704 case SGML_CATA_DOCUMENT:
705 case SGML_CATA_SGMLDECL:
706 break;
707 }
708 cur = cur->next;
709 }
710
711 /*
712 * reserialize it
713 */
714 buf = xmlOutputBufferCreateFile(out, NULL);
715 if (buf == NULL) {
716 xmlFreeDoc(doc);
717 return(-1);
718 }
719 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
720
721 /*
722 * Free it
723 */
724 xmlFreeDoc(doc);
725
726 return(ret);
727}
728
729/**
730 * xmlAddXMLCatalog:
731 * @catal: top of an XML catalog
732 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +0000733 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +0000734 * @replace: the replacement value for the match
735 *
736 * Add an entry in the XML catalog, it may overwrite existing but
737 * different entries.
738 *
739 * Returns 0 if successful, -1 otherwise
740 */
741static int
742xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
743 const xmlChar *orig, const xmlChar *replace) {
744 xmlCatalogEntryPtr cur;
745 xmlCatalogEntryType typ;
746
747 if ((catal == NULL) || (catal->type != XML_CATA_CATALOG))
748 return(-1);
749 typ = xmlGetXMLCatalogEntryType(type);
750 if (typ == XML_CATA_NONE)
751 return(-1);
752
753 cur = catal->children;
754 /*
755 * Might be a simple "update in place"
756 */
757 if (cur != NULL) {
758 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000759 if ((orig != NULL) && (cur->type == typ) &&
760 (xmlStrEqual(orig, cur->name))) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000761 if (cur->value != NULL)
762 xmlFree(cur->value);
763 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +0000764 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +0000765 }
766 if (cur->next == NULL)
767 break;
768 cur = cur->next;
769 }
770 }
771 if (cur == NULL)
772 catal->children = xmlNewCatalogEntry(typ, orig, replace);
773 else
774 cur->next = xmlNewCatalogEntry(typ, orig, replace);
Daniel Veillardcda96922001-08-21 10:56:31 +0000775 return(0);
776}
777
778/**
779 * xmlDelXMLCatalog:
780 * @catal: top of an XML catalog
781 * @value: the value to remove from teh catalog
782 *
783 * Remove entries in the XML catalog where the value or the URI
784 * is equal to @value
785 *
786 * Returns the number of entries removed if successful, -1 otherwise
787 */
788static int
789xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
790 xmlCatalogEntryPtr cur, prev, tmp;
791 int ret = 0;
792
793 if ((catal == NULL) || (catal->type != XML_CATA_CATALOG))
794 return(-1);
795 if (value == NULL)
796 return(-1);
797
798 /*
799 * Scan the children
800 */
801 cur = catal->children;
802 prev = NULL;
803 while (cur != NULL) {
804 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
805 (xmlStrEqual(value, cur->value))) {
806 ret++;
807 tmp = cur;
808 cur = tmp->next;
809 if (prev == NULL) {
810 catal->children = cur;
811 } else {
812 prev->next = cur;
813 }
814 xmlFreeCatalogEntry(tmp);
815 continue;
816 }
817 prev = cur;
818 cur = cur->next;
819 }
820 return(ret);
821}
822
823/**
824 * xmlCatalogGetXMLPublic:
825 * @catal: an XML catalog
826 * @pubId: the public ID string
827 *
828 * Try to lookup the system ID associated to a public ID
829 *
830 * Returns the system ID if found or NULL otherwise.
831 */
832static const xmlChar *
833xmlCatalogGetXMLPublic(xmlCatalogEntryPtr catal, const xmlChar *pubID) {
834 const xmlChar *ret;
835 while (catal != NULL) {
836 switch (catal->type) {
837 case XML_CATA_CATALOG:
838 if (catal->children == NULL) {
839 if (xmlFetchXMLCatalogFile(catal))
840 break;
841 }
842 ret = xmlCatalogGetXMLPublic(catal->children, pubID);
843 if (ret != NULL)
844 return(ret);
845 break;
846 case XML_CATA_NEXT_CATALOG:
847 if (catal->children == NULL) {
848 if (xmlFetchXMLCatalogFile(catal))
849 break;
850 }
851 case XML_CATA_PUBLIC:
852 if (xmlStrEqual(pubID, catal->name))
853 return(catal->value);
854 break;
855 case XML_CATA_SYSTEM:
856 case XML_CATA_REWRITE_SYSTEM:
857 case XML_CATA_DELEGATE_PUBLIC:
858 case XML_CATA_DELEGATE_SYSTEM:
859 case XML_CATA_URI:
860 case XML_CATA_REWRITE_URI:
861 case XML_CATA_DELEGATE_URI:
862 TODO;
863 break;
864
865 case XML_CATA_NONE:
866 case SGML_CATA_SYSTEM:
867 case SGML_CATA_PUBLIC:
868 case SGML_CATA_ENTITY:
869 case SGML_CATA_PENTITY:
870 case SGML_CATA_DOCTYPE:
871 case SGML_CATA_LINKTYPE:
872 case SGML_CATA_NOTATION:
873 case SGML_CATA_DELEGATE:
874 case SGML_CATA_BASE:
875 case SGML_CATA_CATALOG:
876 case SGML_CATA_DOCUMENT:
877 case SGML_CATA_SGMLDECL:
878 /* Ignored entries */
879 break;
880 }
881 catal = catal->next;
882 }
883 return(NULL);
884}
885
886/**
887 * xmlCatalogXMLResolve:
888 * @catal: a catalog list
889 * @pubId: the public ID string
890 * @sysId: the system ID string
891 *
892 * Do a complete resolution lookup of an External Identifier for a
893 * list of catalog entries.
894 *
895 * Implements (or tries to) 7.1. External Identifier Resolution
896 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
897 *
898 * Returns the URI of the resource or NULL if not found
899 */
900static xmlChar *
901xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
902 const xmlChar *sysID) {
903 xmlChar *ret = NULL;
904 xmlCatalogEntryPtr cur;
905 int haveDelegate = 0;
906 int haveNext = 0;
907
908 /*
909 * First tries steps 2/ 3/ 4/ if a system ID is provided.
910 */
911 if (sysID != NULL) {
912 xmlCatalogEntryPtr rewrite = NULL;
913 int lenrewrite = 0, len;
914 cur = catal;
915 haveDelegate = 0;
916 while (cur != NULL) {
917 switch (cur->type) {
918 case XML_CATA_SYSTEM:
919 if (xmlStrEqual(sysID, cur->name))
920 return(xmlStrdup(cur->value));
921 break;
922 case XML_CATA_REWRITE_SYSTEM:
923 len = xmlStrlen(cur->name);
924 if ((len > lenrewrite) &&
925 (!xmlStrncmp(sysID, cur->name, len))) {
926 lenrewrite = len;
927 rewrite = cur;
928 }
929 break;
930 case XML_CATA_DELEGATE_SYSTEM:
931 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
932 haveDelegate++;
933 break;
934 case XML_CATA_NEXT_CATALOG:
935 haveNext++;
936 break;
937 default:
938 break;
939 }
940 cur = cur->next;
941 }
942 if (rewrite != NULL) {
943 ret = xmlStrdup(rewrite->value);
944 if (ret != NULL)
945 ret = xmlStrcat(ret, &sysID[lenrewrite]);
946 return(ret);
947 }
948 if (haveDelegate) {
949 /*
950 * Assume the entries have been sorted by decreasing subscting
951 * matches when the list was produced.
952 */
953 cur = catal;
954 while (cur != NULL) {
955 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
956 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
957 if (cur->children == NULL) {
958 xmlFetchXMLCatalogFile(cur);
959 }
960 if (cur->children != NULL) {
961 TODO /* handle a delegate system entry */
962 }
963 }
964 cur = cur->next;
965 }
966 }
967 }
968 /*
969 * Then tries 5/ 6/ if a public ID is provided
970 */
971 if (pubID != NULL) {
972 cur = catal;
973 haveDelegate = 0;
974 while (cur != NULL) {
975 switch (cur->type) {
976 case XML_CATA_PUBLIC:
977 if (xmlStrEqual(pubID, cur->name))
978 return(xmlStrdup(cur->value));
979 break;
980 case XML_CATA_DELEGATE_PUBLIC:
981 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))
982 haveDelegate++;
983 break;
984 case XML_CATA_NEXT_CATALOG:
985 if (sysID == NULL)
986 haveNext++;
987 break;
988 default:
989 break;
990 }
991 cur = cur->next;
992 }
993 if (haveDelegate) {
994 /*
995 * Assume the entries have been sorted by decreasing subscting
996 * matches when the list was produced.
997 */
998 cur = catal;
999 while (cur != NULL) {
1000 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
1001 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
1002 if (cur->children == NULL) {
1003 xmlFetchXMLCatalogFile(cur);
1004 }
1005 if (cur->children != NULL) {
1006 TODO /* handle a delegate public entry */
1007 }
1008 }
1009 cur = cur->next;
1010 }
1011 }
1012 }
1013 if (haveNext) {
1014 cur = catal;
1015 while (cur != NULL) {
1016 if (cur->type == XML_CATA_NEXT_CATALOG) {
1017 if (cur->children == NULL) {
1018 xmlFetchXMLCatalogFile(cur);
1019 }
1020 if (cur->children != NULL) {
1021 xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1022 }
1023 }
1024 cur = cur->next;
1025 }
1026 }
1027
1028 return(NULL);
1029}
1030
1031/**
1032 * xmlCatalogListXMLResolve:
1033 * @catal: a catalog list
1034 * @pubId: the public ID string
1035 * @sysId: the system ID string
1036 *
1037 * Do a complete resolution lookup of an External Identifier for a
1038 * list of catalogs
1039 *
1040 * Implements (or tries to) 7.1. External Identifier Resolution
1041 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1042 *
1043 * Returns the URI of the resource or NULL if not found
1044 */
1045static xmlChar *
1046xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1047 const xmlChar *sysID) {
1048 xmlChar *ret = NULL;
1049 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID))) {
1050 TODO /* convert to PublicId */
1051 }
1052 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID))) {
1053 TODO /* convert to PublicId and check */
1054 }
1055 while (catal != NULL) {
1056 if (catal->type == XML_CATA_CATALOG) {
1057 if (catal->children == NULL) {
1058 /*
1059 * Construct the list on the fly, then double check
1060 * in case of threaded program that it hasn't already
1061 * being built by a concurrent thread.
1062 xmlCatalogEntryPtr list;
1063
1064 list =
1065 */
1066 TODO
1067 }
1068 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1069 if (ret != NULL)
1070 return(ret);
1071 }
1072 catal = catal->next;
1073 }
1074 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001075}
1076
1077/************************************************************************
1078 * *
1079 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001080 * *
1081 ************************************************************************/
1082
1083
1084#define RAW *cur
1085#define NEXT cur++;
1086#define SKIP(x) cur += x;
1087
1088#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1089
1090static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001091xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001092 if ((cur[0] != '-') || (cur[1] != '-'))
1093 return(cur);
1094 SKIP(2);
1095 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1096 NEXT;
1097 if (cur[0] == 0) {
1098 return(NULL);
1099 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001100 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001101}
1102
1103static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001104xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001105 xmlChar *buf = NULL;
1106 int len = 0;
1107 int size = 50;
1108 xmlChar stop;
1109 int count = 0;
1110
1111 *id = NULL;
1112
1113 if (RAW == '"') {
1114 NEXT;
1115 stop = '"';
1116 } else if (RAW == '\'') {
1117 NEXT;
1118 stop = '\'';
1119 } else {
1120 stop = ' ';
1121 }
1122 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1123 if (buf == NULL) {
1124 xmlGenericError(xmlGenericErrorContext,
1125 "malloc of %d byte failed\n", size);
1126 return(NULL);
1127 }
1128 while (xmlIsPubidChar(*cur)) {
1129 if ((*cur == stop) && (stop != ' '))
1130 break;
1131 if ((stop == ' ') && (IS_BLANK(*cur)))
1132 break;
1133 if (len + 1 >= size) {
1134 size *= 2;
1135 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1136 if (buf == NULL) {
1137 xmlGenericError(xmlGenericErrorContext,
1138 "realloc of %d byte failed\n", size);
1139 return(NULL);
1140 }
1141 }
1142 buf[len++] = *cur;
1143 count++;
1144 NEXT;
1145 }
1146 buf[len] = 0;
1147 if (stop == ' ') {
1148 if (!IS_BLANK(*cur)) {
1149 xmlFree(buf);
1150 return(NULL);
1151 }
1152 } else {
1153 if (*cur != stop) {
1154 xmlFree(buf);
1155 return(NULL);
1156 }
1157 NEXT;
1158 }
1159 *id = buf;
1160 return(cur);
1161}
1162
1163static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001164xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001165 xmlChar buf[XML_MAX_NAMELEN + 5];
1166 int len = 0;
1167 int c;
1168
1169 *name = NULL;
1170
1171 /*
1172 * Handler for more complex cases
1173 */
1174 c = *cur;
1175 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
1176 return(NULL);
1177 }
1178
1179 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
1180 (c == '.') || (c == '-') ||
1181 (c == '_') || (c == ':'))) {
1182 buf[len++] = c;
1183 cur++;
1184 c = *cur;
1185 if (len >= XML_MAX_NAMELEN)
1186 return(NULL);
1187 }
1188 *name = xmlStrndup(buf, len);
1189 return(cur);
1190}
1191
Daniel Veillard344cee72001-08-20 00:08:40 +00001192static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00001193xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001194 xmlCatalogEntryType type = XML_CATA_NONE;
1195 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
1196 type = SGML_CATA_SYSTEM;
1197 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
1198 type = SGML_CATA_PUBLIC;
1199 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1200 type = SGML_CATA_DELEGATE;
1201 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
1202 type = SGML_CATA_ENTITY;
1203 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
1204 type = SGML_CATA_DOCTYPE;
1205 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
1206 type = SGML_CATA_LINKTYPE;
1207 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
1208 type = SGML_CATA_NOTATION;
1209 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
1210 type = SGML_CATA_SGMLDECL;
1211 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
1212 type = SGML_CATA_DOCUMENT;
1213 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
1214 type = SGML_CATA_CATALOG;
1215 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
1216 type = SGML_CATA_BASE;
1217 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1218 type = SGML_CATA_DELEGATE;
1219 return(type);
1220}
1221
Daniel Veillarda7374592001-05-10 14:17:55 +00001222static int
Daniel Veillardcda96922001-08-21 10:56:31 +00001223xmlParseSGMLCatalog(const xmlChar *value, const char *file) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001224 const xmlChar *cur = value;
1225 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001226 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00001227
1228 if ((cur == NULL) || (file == NULL))
1229 return(-1);
1230 base = xmlStrdup((const xmlChar *) file);
1231
1232 while ((cur != NULL) && (cur[0] != '0')) {
1233 SKIP_BLANKS;
1234 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001235 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00001236 if (cur == NULL) {
1237 /* error */
1238 break;
1239 }
1240 } else {
1241 xmlChar *sysid = NULL;
1242 xmlChar *name = NULL;
1243 xmlCatalogEntryType type = XML_CATA_NONE;
1244
Daniel Veillardcda96922001-08-21 10:56:31 +00001245 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001246 if (name == NULL) {
1247 /* error */
1248 break;
1249 }
1250 if (!IS_BLANK(*cur)) {
1251 /* error */
1252 break;
1253 }
1254 SKIP_BLANKS;
1255 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001256 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00001257 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001258 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00001259 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001260 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001261 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001262 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00001263 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001264 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001265 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001266 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001267 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001268 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00001269 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001270 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001271 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001272 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00001273 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001274 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00001275 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001276 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001277 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001278 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001279 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
1280 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001281 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001282 if (name == NULL) {
1283 /* error */
1284 break;
1285 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001286 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001287 continue;
1288 }
1289 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001290 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001291
1292 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001293 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00001294 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00001295 type = SGML_CATA_PENTITY;
1296 case SGML_CATA_PENTITY:
1297 case SGML_CATA_DOCTYPE:
1298 case SGML_CATA_LINKTYPE:
1299 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00001300 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001301 if (cur == NULL) {
1302 /* error */
1303 break;
1304 }
1305 if (!IS_BLANK(*cur)) {
1306 /* error */
1307 break;
1308 }
1309 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001310 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001311 if (cur == NULL) {
1312 /* error */
1313 break;
1314 }
1315 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001316 case SGML_CATA_PUBLIC:
1317 case SGML_CATA_SYSTEM:
1318 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00001319 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001320 if (cur == NULL) {
1321 /* error */
1322 break;
1323 }
1324 if (!IS_BLANK(*cur)) {
1325 /* error */
1326 break;
1327 }
1328 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001329 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001330 if (cur == NULL) {
1331 /* error */
1332 break;
1333 }
1334 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001335 case SGML_CATA_BASE:
1336 case SGML_CATA_CATALOG:
1337 case SGML_CATA_DOCUMENT:
1338 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00001339 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001340 if (cur == NULL) {
1341 /* error */
1342 break;
1343 }
1344 break;
1345 default:
1346 break;
1347 }
1348 if (cur == NULL) {
1349 if (name != NULL)
1350 xmlFree(name);
1351 if (sysid != NULL)
1352 xmlFree(sysid);
1353 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001354 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001355 if (base != NULL)
1356 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001357 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00001358 } else if ((type == SGML_CATA_PUBLIC) ||
1359 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001360 xmlChar *filename;
1361
1362 filename = xmlBuildURI(sysid, base);
1363 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001364 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00001365
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001366 entry = xmlNewCatalogEntry(type, name, filename);
1367 res = xmlHashAddEntry(xmlDefaultCatalog, name, entry);
1368 if (res < 0) {
1369 xmlFreeCatalogEntry(entry);
1370 }
1371 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00001372 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001373
Daniel Veillard344cee72001-08-20 00:08:40 +00001374 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001375 xmlChar *filename;
1376
1377 filename = xmlBuildURI(sysid, base);
1378 if (filename != NULL) {
1379 xmlLoadCatalog((const char *)filename);
1380 xmlFree(filename);
1381 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001382 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001383 /*
1384 * drop anything else we won't handle it
1385 */
1386 if (name != NULL)
1387 xmlFree(name);
1388 if (sysid != NULL)
1389 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001390 }
1391 }
1392 if (base != NULL)
1393 xmlFree(base);
1394 if (cur == NULL)
1395 return(-1);
1396 return(0);
1397}
1398
Daniel Veillardcda96922001-08-21 10:56:31 +00001399/**
1400 * xmlCatalogGetSGMLPublic:
1401 * @catal: an SGML catalog hash
1402 * @pubId: the public ID string
1403 *
1404 * Try to lookup the system ID associated to a public ID
1405 *
1406 * Returns the system ID if found or NULL otherwise.
1407 */
1408static const xmlChar *
1409xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
1410 xmlCatalogEntryPtr entry;
1411
1412 if (catal == NULL)
1413 return(NULL);
1414
1415 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
1416 if (entry == NULL)
1417 return(NULL);
1418 if (entry->type == SGML_CATA_PUBLIC)
1419 return(entry->value);
1420 return(NULL);
1421}
1422
1423/**
1424 * xmlCatalogSGMLResolve:
1425 * @pubId: the public ID string
1426 * @sysId: the system ID string
1427 *
1428 * Do a complete resolution lookup of an External Identifier
1429 *
1430 * Returns the URI of the resource or NULL if not found
1431 */
1432static const xmlChar *
1433xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) {
1434 TODO
1435 return(NULL);
1436}
1437
Daniel Veillarda7374592001-05-10 14:17:55 +00001438/************************************************************************
1439 * *
1440 * Public interfaces *
1441 * *
1442 ************************************************************************/
1443
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001444/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001445 * xmlLoadCatalog:
1446 * @filename: a file path
1447 *
Daniel Veillard81418e32001-05-22 15:08:55 +00001448 * Load the catalog and makes its definitions effective for the default
1449 * external entity loader. It will recuse in CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001450 * TODO: this function is not thread safe, catalog initialization should
1451 * be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00001452 *
1453 * Returns 0 in case of success -1 in case of error
1454 */
1455int
1456xmlLoadCatalog(const char *filename) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001457 int fd, len, ret, i;
Daniel Veillarda7374592001-05-10 14:17:55 +00001458 struct stat info;
1459 xmlChar *content;
1460
1461 if (filename == NULL)
1462 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001463
Daniel Veillarda7374592001-05-10 14:17:55 +00001464 if (xmlDefaultCatalog == NULL)
1465 xmlDefaultCatalog = xmlHashCreate(20);
1466 if (xmlDefaultCatalog == NULL)
1467 return(-1);
1468
1469 if (stat(filename, &info) < 0)
1470 return(-1);
1471
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001472 /*
1473 * Prevent loops
1474 */
1475 for (i = 0;i < catalNr;i++) {
Daniel Veillard81418e32001-05-22 15:08:55 +00001476 if (xmlStrEqual((const xmlChar *)catalTab[i],
1477 (const xmlChar *)filename)) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001478 xmlGenericError(xmlGenericErrorContext,
1479 "xmlLoadCatalog: %s seems to induce a loop\n",
1480 filename);
1481 return(-1);
1482 }
1483 }
1484 if (catalNr >= catalMax) {
1485 xmlGenericError(xmlGenericErrorContext,
1486 "xmlLoadCatalog: %s catalog list too deep\n",
1487 filename);
1488 return(-1);
1489 }
1490 catalTab[catalNr++] = filename;
1491
1492 if ((fd = open(filename, O_RDONLY)) < 0) {
1493 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001494 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001495 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001496
1497 content = xmlMalloc(info.st_size + 10);
1498 if (content == NULL) {
1499 xmlGenericError(xmlGenericErrorContext,
1500 "realloc of %d byte failed\n", info.st_size + 10);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001501 catalNr--;
1502 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00001503 }
1504 len = read(fd, content, info.st_size);
1505 if (len < 0) {
1506 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001507 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001508 return(-1);
1509 }
1510 content[len] = 0;
1511 close(fd);
1512
Daniel Veillard344cee72001-08-20 00:08:40 +00001513 if ((content[0] == ' ') || (content[0] == '-') ||
1514 ((content[0] >= 'A') && (content[0] <= 'Z')) ||
1515 ((content[0] >= 'a') && (content[0] <= 'z')))
Daniel Veillardcda96922001-08-21 10:56:31 +00001516 ret = xmlParseSGMLCatalog(content, filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001517 else {
1518 xmlCatalogEntryPtr catal, tmp;
1519 /* TODO: allow to switch the default preference */
1520 catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
1521 if (catal != NULL) {
1522 if (xmlDefaultXMLCatalogList == NULL)
1523 xmlDefaultXMLCatalogList = catal;
1524 else {
1525 tmp = xmlDefaultXMLCatalogList;
1526 while (tmp->next != NULL)
1527 tmp = tmp->next;
1528 tmp->next = catal;
1529 }
1530 ret = 0;
1531 } else
1532 ret = -1;
1533 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001534 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001535 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001536 return(ret);
1537}
1538
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001539/**
Daniel Veillard81418e32001-05-22 15:08:55 +00001540 * xmlLoadCatalogs:
1541 * @paths: a list of file path separated by ':' or spaces
1542 *
1543 * Load the catalogs and makes their definitions effective for the default
1544 * external entity loader.
1545 * TODO: this function is not thread safe, catalog initialization should
1546 * be done once at startup
1547 */
1548void
1549xmlLoadCatalogs(const char *pathss) {
1550 const char *cur;
1551 const char *paths;
1552 xmlChar *path;
1553
1554 cur = pathss;
1555 while ((cur != NULL) && (*cur != 0)) {
1556 while (IS_BLANK(*cur)) cur++;
1557 if (*cur != 0) {
1558 paths = cur;
1559 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
1560 cur++;
1561 path = xmlStrndup((const xmlChar *)paths, cur - paths);
1562 if (path != NULL) {
1563 xmlLoadCatalog((const char *) path);
1564 xmlFree(path);
1565 }
1566 }
1567 while (*cur == ':')
1568 cur++;
1569 }
1570}
1571
Daniel Veillarda7374592001-05-10 14:17:55 +00001572/**
1573 * xmlCatalogCleanup:
1574 *
1575 * Free up all the memory associated with catalogs
1576 */
1577void
1578xmlCatalogCleanup(void) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001579 if (xmlDefaultXMLCatalogList != NULL)
1580 xmlFreeCatalogEntryList(xmlDefaultXMLCatalogList);
Daniel Veillarda7374592001-05-10 14:17:55 +00001581 if (xmlDefaultCatalog != NULL)
1582 xmlHashFree(xmlDefaultCatalog,
1583 (xmlHashDeallocator) xmlFreeCatalogEntry);
1584 xmlDefaultCatalog = NULL;
1585}
1586
1587/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001588 * xmlCatalogGetSystem:
1589 * @sysId: the system ID string
Daniel Veillarda7374592001-05-10 14:17:55 +00001590 *
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001591 * Try to lookup the resource associated to a system ID
1592 *
1593 * Returns the resource name if found or NULL otherwise.
Daniel Veillarda7374592001-05-10 14:17:55 +00001594 */
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001595const xmlChar *
1596xmlCatalogGetSystem(const xmlChar *sysID) {
1597 xmlCatalogEntryPtr entry;
1598
1599 if ((sysID == NULL) || (xmlDefaultCatalog == NULL))
1600 return(NULL);
1601 entry = (xmlCatalogEntryPtr) xmlHashLookup(xmlDefaultCatalog, sysID);
1602 if (entry == NULL)
1603 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001604 if (entry->type == SGML_CATA_SYSTEM)
1605 return(entry->value);
1606 return(NULL);
1607}
1608
1609/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001610 * xmlCatalogGetPublic:
1611 * @pubId: the public ID string
1612 *
1613 * Try to lookup the system ID associated to a public ID
1614 *
1615 * Returns the system ID if found or NULL otherwise.
1616 */
1617const xmlChar *
1618xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001619 xmlCatalogEntryPtr catal;
1620 const xmlChar *ret;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001621
Daniel Veillard344cee72001-08-20 00:08:40 +00001622 if (pubID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001623 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001624
1625 /*
1626 * Check first the XML catalogs
1627 */
1628 catal = xmlDefaultXMLCatalogList;
1629 if (catal != NULL) {
1630 ret = xmlCatalogGetXMLPublic(catal, pubID);
1631 if (ret != NULL)
1632 return(ret);
1633 }
1634
1635 if (xmlDefaultCatalog != NULL)
1636 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001637 return(NULL);
1638}
Daniel Veillard344cee72001-08-20 00:08:40 +00001639
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001640/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001641 * xmlCatalogResolve:
1642 * @pubId: the public ID string
1643 * @sysId: the system ID string
1644 *
1645 * Do a complete resolution lookup of an External Identifier
1646 *
1647 * Returns the URI of the resource or NULL if not found, it must be freed
1648 * by the caller.
1649 */
1650xmlChar *
1651xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
1652 if (xmlDefaultXMLCatalogList != NULL) {
1653 return(xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, sysID));
1654 } else {
1655 return(xmlCatalogSGMLResolve(pubID, sysID));
1656 }
1657}
1658
1659/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001660 * xmlCatalogDump:
1661 * @out: the file.
1662 *
1663 * Free up all the memory associated with catalogs
1664 */
1665void
1666xmlCatalogDump(FILE *out) {
1667 if (out == NULL)
1668 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00001669
1670 if (xmlDefaultXMLCatalogList != NULL) {
1671 xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList);
1672 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001673 xmlHashScan(xmlDefaultCatalog,
1674 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00001675 }
1676}
1677
1678/**
1679 * xmlCatalogAdd:
1680 * @type: the type of record to add to the catalog
1681 * @orig: the system, public or prefix to match
1682 * @replace: the replacement value for the match
1683 *
1684 * Add an entry in the catalog, it may overwrite existing but
1685 * different entries.
1686 *
1687 * Returns 0 if successful, -1 otherwise
1688 */
1689int
1690xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
1691 int res = -1;
1692
1693 if (xmlDefaultXMLCatalogList != NULL) {
1694 res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
1695 } else if (xmlDefaultCatalog != NULL) {
1696 xmlCatalogEntryType typ;
1697
Daniel Veillardcda96922001-08-21 10:56:31 +00001698 typ = xmlGetSGMLCatalogEntryType(type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001699 if (type != XML_CATA_NONE) {
1700 xmlCatalogEntryPtr entry;
1701 entry = xmlNewCatalogEntry(typ, orig, replace);
1702 res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
1703 }
1704 }
1705 return(res);
1706}
1707
1708/**
1709 * xmlCatalogRemove:
1710 * @value: the value to remove
1711 *
1712 * Remove an entry from the catalog
1713 *
1714 * Returns 0 if successful, -1 otherwise
1715 */
1716int
1717xmlCatalogRemove(const xmlChar *value) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001718 int res = -1;
1719
1720 if (xmlDefaultXMLCatalogList != NULL) {
1721 res = xmlDelXMLCatalog(xmlDefaultXMLCatalogList, value);
1722 } else if (xmlDefaultCatalog != NULL) {
1723 TODO
1724 }
1725 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00001726}
1727
1728/**
1729 * xmlCatalogSetDebug:
1730 * @level: the debug level of catalogs required
1731 *
1732 * Used to set the debug level for catalog operation, 0 disable
1733 * debugging, 1 enable it
1734 *
1735 * Returns the previous value of the catalog debugging level
1736 */
1737int
1738xmlCatalogSetDebug(int level) {
1739 int ret = xmlDebugCatalogs;
1740
1741 if (level <= 0)
1742 xmlDebugCatalogs = 0;
1743 else
1744 xmlDebugCatalogs = level;
1745 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00001746}
1747#endif /* LIBXML_CATALOG_ENABLED */