blob: 21270d4432dc969655df9451ec37637e14846759 [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) {
Daniel Veillard64339542001-08-21 12:57:59 +00001021 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1022 if (ret != NULL)
1023 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001024 }
1025 }
1026 cur = cur->next;
1027 }
1028 }
1029
1030 return(NULL);
1031}
1032
1033/**
1034 * xmlCatalogListXMLResolve:
1035 * @catal: a catalog list
1036 * @pubId: the public ID string
1037 * @sysId: the system ID string
1038 *
1039 * Do a complete resolution lookup of an External Identifier for a
1040 * list of catalogs
1041 *
1042 * Implements (or tries to) 7.1. External Identifier Resolution
1043 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1044 *
1045 * Returns the URI of the resource or NULL if not found
1046 */
1047static xmlChar *
1048xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1049 const xmlChar *sysID) {
1050 xmlChar *ret = NULL;
1051 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID))) {
1052 TODO /* convert to PublicId */
1053 }
1054 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID))) {
1055 TODO /* convert to PublicId and check */
1056 }
1057 while (catal != NULL) {
1058 if (catal->type == XML_CATA_CATALOG) {
1059 if (catal->children == NULL) {
1060 /*
1061 * Construct the list on the fly, then double check
1062 * in case of threaded program that it hasn't already
1063 * being built by a concurrent thread.
1064 xmlCatalogEntryPtr list;
1065
1066 list =
1067 */
1068 TODO
1069 }
1070 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1071 if (ret != NULL)
1072 return(ret);
1073 }
1074 catal = catal->next;
1075 }
1076 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001077}
1078
1079/************************************************************************
1080 * *
1081 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001082 * *
1083 ************************************************************************/
1084
1085
1086#define RAW *cur
1087#define NEXT cur++;
1088#define SKIP(x) cur += x;
1089
1090#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1091
1092static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001093xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001094 if ((cur[0] != '-') || (cur[1] != '-'))
1095 return(cur);
1096 SKIP(2);
1097 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1098 NEXT;
1099 if (cur[0] == 0) {
1100 return(NULL);
1101 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001102 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001103}
1104
1105static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001106xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001107 xmlChar *buf = NULL;
1108 int len = 0;
1109 int size = 50;
1110 xmlChar stop;
1111 int count = 0;
1112
1113 *id = NULL;
1114
1115 if (RAW == '"') {
1116 NEXT;
1117 stop = '"';
1118 } else if (RAW == '\'') {
1119 NEXT;
1120 stop = '\'';
1121 } else {
1122 stop = ' ';
1123 }
1124 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1125 if (buf == NULL) {
1126 xmlGenericError(xmlGenericErrorContext,
1127 "malloc of %d byte failed\n", size);
1128 return(NULL);
1129 }
1130 while (xmlIsPubidChar(*cur)) {
1131 if ((*cur == stop) && (stop != ' '))
1132 break;
1133 if ((stop == ' ') && (IS_BLANK(*cur)))
1134 break;
1135 if (len + 1 >= size) {
1136 size *= 2;
1137 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1138 if (buf == NULL) {
1139 xmlGenericError(xmlGenericErrorContext,
1140 "realloc of %d byte failed\n", size);
1141 return(NULL);
1142 }
1143 }
1144 buf[len++] = *cur;
1145 count++;
1146 NEXT;
1147 }
1148 buf[len] = 0;
1149 if (stop == ' ') {
1150 if (!IS_BLANK(*cur)) {
1151 xmlFree(buf);
1152 return(NULL);
1153 }
1154 } else {
1155 if (*cur != stop) {
1156 xmlFree(buf);
1157 return(NULL);
1158 }
1159 NEXT;
1160 }
1161 *id = buf;
1162 return(cur);
1163}
1164
1165static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001166xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001167 xmlChar buf[XML_MAX_NAMELEN + 5];
1168 int len = 0;
1169 int c;
1170
1171 *name = NULL;
1172
1173 /*
1174 * Handler for more complex cases
1175 */
1176 c = *cur;
1177 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
1178 return(NULL);
1179 }
1180
1181 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
1182 (c == '.') || (c == '-') ||
1183 (c == '_') || (c == ':'))) {
1184 buf[len++] = c;
1185 cur++;
1186 c = *cur;
1187 if (len >= XML_MAX_NAMELEN)
1188 return(NULL);
1189 }
1190 *name = xmlStrndup(buf, len);
1191 return(cur);
1192}
1193
Daniel Veillard344cee72001-08-20 00:08:40 +00001194static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00001195xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001196 xmlCatalogEntryType type = XML_CATA_NONE;
1197 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
1198 type = SGML_CATA_SYSTEM;
1199 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
1200 type = SGML_CATA_PUBLIC;
1201 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1202 type = SGML_CATA_DELEGATE;
1203 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
1204 type = SGML_CATA_ENTITY;
1205 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
1206 type = SGML_CATA_DOCTYPE;
1207 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
1208 type = SGML_CATA_LINKTYPE;
1209 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
1210 type = SGML_CATA_NOTATION;
1211 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
1212 type = SGML_CATA_SGMLDECL;
1213 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
1214 type = SGML_CATA_DOCUMENT;
1215 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
1216 type = SGML_CATA_CATALOG;
1217 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
1218 type = SGML_CATA_BASE;
1219 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1220 type = SGML_CATA_DELEGATE;
1221 return(type);
1222}
1223
Daniel Veillarda7374592001-05-10 14:17:55 +00001224static int
Daniel Veillardcda96922001-08-21 10:56:31 +00001225xmlParseSGMLCatalog(const xmlChar *value, const char *file) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001226 const xmlChar *cur = value;
1227 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001228 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00001229
1230 if ((cur == NULL) || (file == NULL))
1231 return(-1);
1232 base = xmlStrdup((const xmlChar *) file);
1233
1234 while ((cur != NULL) && (cur[0] != '0')) {
1235 SKIP_BLANKS;
1236 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001237 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00001238 if (cur == NULL) {
1239 /* error */
1240 break;
1241 }
1242 } else {
1243 xmlChar *sysid = NULL;
1244 xmlChar *name = NULL;
1245 xmlCatalogEntryType type = XML_CATA_NONE;
1246
Daniel Veillardcda96922001-08-21 10:56:31 +00001247 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001248 if (name == NULL) {
1249 /* error */
1250 break;
1251 }
1252 if (!IS_BLANK(*cur)) {
1253 /* error */
1254 break;
1255 }
1256 SKIP_BLANKS;
1257 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001258 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00001259 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001260 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00001261 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001262 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001263 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001264 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00001265 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001266 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001267 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001268 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001269 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001270 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00001271 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001272 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001273 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001274 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00001275 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001276 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00001277 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001278 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001279 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001280 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001281 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
1282 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001283 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001284 if (name == NULL) {
1285 /* error */
1286 break;
1287 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001288 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001289 continue;
1290 }
1291 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001292 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001293
1294 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001295 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00001296 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00001297 type = SGML_CATA_PENTITY;
1298 case SGML_CATA_PENTITY:
1299 case SGML_CATA_DOCTYPE:
1300 case SGML_CATA_LINKTYPE:
1301 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00001302 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001303 if (cur == NULL) {
1304 /* error */
1305 break;
1306 }
1307 if (!IS_BLANK(*cur)) {
1308 /* error */
1309 break;
1310 }
1311 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001312 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001313 if (cur == NULL) {
1314 /* error */
1315 break;
1316 }
1317 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001318 case SGML_CATA_PUBLIC:
1319 case SGML_CATA_SYSTEM:
1320 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00001321 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001322 if (cur == NULL) {
1323 /* error */
1324 break;
1325 }
1326 if (!IS_BLANK(*cur)) {
1327 /* error */
1328 break;
1329 }
1330 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001331 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001332 if (cur == NULL) {
1333 /* error */
1334 break;
1335 }
1336 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001337 case SGML_CATA_BASE:
1338 case SGML_CATA_CATALOG:
1339 case SGML_CATA_DOCUMENT:
1340 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00001341 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001342 if (cur == NULL) {
1343 /* error */
1344 break;
1345 }
1346 break;
1347 default:
1348 break;
1349 }
1350 if (cur == NULL) {
1351 if (name != NULL)
1352 xmlFree(name);
1353 if (sysid != NULL)
1354 xmlFree(sysid);
1355 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001356 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001357 if (base != NULL)
1358 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001359 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00001360 } else if ((type == SGML_CATA_PUBLIC) ||
1361 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001362 xmlChar *filename;
1363
1364 filename = xmlBuildURI(sysid, base);
1365 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001366 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00001367
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001368 entry = xmlNewCatalogEntry(type, name, filename);
1369 res = xmlHashAddEntry(xmlDefaultCatalog, name, entry);
1370 if (res < 0) {
1371 xmlFreeCatalogEntry(entry);
1372 }
1373 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00001374 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001375
Daniel Veillard344cee72001-08-20 00:08:40 +00001376 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001377 xmlChar *filename;
1378
1379 filename = xmlBuildURI(sysid, base);
1380 if (filename != NULL) {
1381 xmlLoadCatalog((const char *)filename);
1382 xmlFree(filename);
1383 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001384 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001385 /*
1386 * drop anything else we won't handle it
1387 */
1388 if (name != NULL)
1389 xmlFree(name);
1390 if (sysid != NULL)
1391 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001392 }
1393 }
1394 if (base != NULL)
1395 xmlFree(base);
1396 if (cur == NULL)
1397 return(-1);
1398 return(0);
1399}
1400
Daniel Veillardcda96922001-08-21 10:56:31 +00001401/**
1402 * xmlCatalogGetSGMLPublic:
1403 * @catal: an SGML catalog hash
1404 * @pubId: the public ID string
1405 *
1406 * Try to lookup the system ID associated to a public ID
1407 *
1408 * Returns the system ID if found or NULL otherwise.
1409 */
1410static const xmlChar *
1411xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
1412 xmlCatalogEntryPtr entry;
1413
1414 if (catal == NULL)
1415 return(NULL);
1416
1417 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
1418 if (entry == NULL)
1419 return(NULL);
1420 if (entry->type == SGML_CATA_PUBLIC)
1421 return(entry->value);
1422 return(NULL);
1423}
1424
1425/**
1426 * xmlCatalogSGMLResolve:
1427 * @pubId: the public ID string
1428 * @sysId: the system ID string
1429 *
1430 * Do a complete resolution lookup of an External Identifier
1431 *
1432 * Returns the URI of the resource or NULL if not found
1433 */
1434static const xmlChar *
1435xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) {
1436 TODO
1437 return(NULL);
1438}
1439
Daniel Veillarda7374592001-05-10 14:17:55 +00001440/************************************************************************
1441 * *
1442 * Public interfaces *
1443 * *
1444 ************************************************************************/
1445
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001446/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001447 * xmlLoadCatalog:
1448 * @filename: a file path
1449 *
Daniel Veillard81418e32001-05-22 15:08:55 +00001450 * Load the catalog and makes its definitions effective for the default
1451 * external entity loader. It will recuse in CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001452 * TODO: this function is not thread safe, catalog initialization should
1453 * be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00001454 *
1455 * Returns 0 in case of success -1 in case of error
1456 */
1457int
1458xmlLoadCatalog(const char *filename) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001459 int fd, len, ret, i;
Daniel Veillarda7374592001-05-10 14:17:55 +00001460 struct stat info;
1461 xmlChar *content;
1462
1463 if (filename == NULL)
1464 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001465
Daniel Veillarda7374592001-05-10 14:17:55 +00001466 if (xmlDefaultCatalog == NULL)
1467 xmlDefaultCatalog = xmlHashCreate(20);
1468 if (xmlDefaultCatalog == NULL)
1469 return(-1);
1470
1471 if (stat(filename, &info) < 0)
1472 return(-1);
1473
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001474 /*
1475 * Prevent loops
1476 */
1477 for (i = 0;i < catalNr;i++) {
Daniel Veillard81418e32001-05-22 15:08:55 +00001478 if (xmlStrEqual((const xmlChar *)catalTab[i],
1479 (const xmlChar *)filename)) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001480 xmlGenericError(xmlGenericErrorContext,
1481 "xmlLoadCatalog: %s seems to induce a loop\n",
1482 filename);
1483 return(-1);
1484 }
1485 }
1486 if (catalNr >= catalMax) {
1487 xmlGenericError(xmlGenericErrorContext,
1488 "xmlLoadCatalog: %s catalog list too deep\n",
1489 filename);
1490 return(-1);
1491 }
1492 catalTab[catalNr++] = filename;
1493
1494 if ((fd = open(filename, O_RDONLY)) < 0) {
1495 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001496 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001497 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001498
1499 content = xmlMalloc(info.st_size + 10);
1500 if (content == NULL) {
1501 xmlGenericError(xmlGenericErrorContext,
1502 "realloc of %d byte failed\n", info.st_size + 10);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001503 catalNr--;
1504 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00001505 }
1506 len = read(fd, content, info.st_size);
1507 if (len < 0) {
1508 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001509 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001510 return(-1);
1511 }
1512 content[len] = 0;
1513 close(fd);
1514
Daniel Veillard344cee72001-08-20 00:08:40 +00001515 if ((content[0] == ' ') || (content[0] == '-') ||
1516 ((content[0] >= 'A') && (content[0] <= 'Z')) ||
1517 ((content[0] >= 'a') && (content[0] <= 'z')))
Daniel Veillardcda96922001-08-21 10:56:31 +00001518 ret = xmlParseSGMLCatalog(content, filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001519 else {
1520 xmlCatalogEntryPtr catal, tmp;
1521 /* TODO: allow to switch the default preference */
1522 catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
1523 if (catal != NULL) {
1524 if (xmlDefaultXMLCatalogList == NULL)
1525 xmlDefaultXMLCatalogList = catal;
1526 else {
1527 tmp = xmlDefaultXMLCatalogList;
1528 while (tmp->next != NULL)
1529 tmp = tmp->next;
1530 tmp->next = catal;
1531 }
1532 ret = 0;
1533 } else
1534 ret = -1;
1535 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001536 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001537 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001538 return(ret);
1539}
1540
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001541/**
Daniel Veillard81418e32001-05-22 15:08:55 +00001542 * xmlLoadCatalogs:
1543 * @paths: a list of file path separated by ':' or spaces
1544 *
1545 * Load the catalogs and makes their definitions effective for the default
1546 * external entity loader.
1547 * TODO: this function is not thread safe, catalog initialization should
1548 * be done once at startup
1549 */
1550void
1551xmlLoadCatalogs(const char *pathss) {
1552 const char *cur;
1553 const char *paths;
1554 xmlChar *path;
1555
1556 cur = pathss;
1557 while ((cur != NULL) && (*cur != 0)) {
1558 while (IS_BLANK(*cur)) cur++;
1559 if (*cur != 0) {
1560 paths = cur;
1561 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
1562 cur++;
1563 path = xmlStrndup((const xmlChar *)paths, cur - paths);
1564 if (path != NULL) {
1565 xmlLoadCatalog((const char *) path);
1566 xmlFree(path);
1567 }
1568 }
1569 while (*cur == ':')
1570 cur++;
1571 }
1572}
1573
Daniel Veillarda7374592001-05-10 14:17:55 +00001574/**
1575 * xmlCatalogCleanup:
1576 *
1577 * Free up all the memory associated with catalogs
1578 */
1579void
1580xmlCatalogCleanup(void) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001581 if (xmlDefaultXMLCatalogList != NULL)
1582 xmlFreeCatalogEntryList(xmlDefaultXMLCatalogList);
Daniel Veillarda7374592001-05-10 14:17:55 +00001583 if (xmlDefaultCatalog != NULL)
1584 xmlHashFree(xmlDefaultCatalog,
1585 (xmlHashDeallocator) xmlFreeCatalogEntry);
1586 xmlDefaultCatalog = NULL;
1587}
1588
1589/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001590 * xmlCatalogGetSystem:
1591 * @sysId: the system ID string
Daniel Veillarda7374592001-05-10 14:17:55 +00001592 *
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001593 * Try to lookup the resource associated to a system ID
1594 *
1595 * Returns the resource name if found or NULL otherwise.
Daniel Veillarda7374592001-05-10 14:17:55 +00001596 */
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001597const xmlChar *
1598xmlCatalogGetSystem(const xmlChar *sysID) {
1599 xmlCatalogEntryPtr entry;
1600
1601 if ((sysID == NULL) || (xmlDefaultCatalog == NULL))
1602 return(NULL);
1603 entry = (xmlCatalogEntryPtr) xmlHashLookup(xmlDefaultCatalog, sysID);
1604 if (entry == NULL)
1605 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001606 if (entry->type == SGML_CATA_SYSTEM)
1607 return(entry->value);
1608 return(NULL);
1609}
1610
1611/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001612 * xmlCatalogGetPublic:
1613 * @pubId: the public ID string
1614 *
1615 * Try to lookup the system ID associated to a public ID
1616 *
1617 * Returns the system ID if found or NULL otherwise.
1618 */
1619const xmlChar *
1620xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001621 xmlCatalogEntryPtr catal;
1622 const xmlChar *ret;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001623
Daniel Veillard344cee72001-08-20 00:08:40 +00001624 if (pubID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001625 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001626
1627 /*
1628 * Check first the XML catalogs
1629 */
1630 catal = xmlDefaultXMLCatalogList;
1631 if (catal != NULL) {
1632 ret = xmlCatalogGetXMLPublic(catal, pubID);
1633 if (ret != NULL)
1634 return(ret);
1635 }
1636
1637 if (xmlDefaultCatalog != NULL)
1638 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001639 return(NULL);
1640}
Daniel Veillard344cee72001-08-20 00:08:40 +00001641
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001642/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001643 * xmlCatalogResolve:
1644 * @pubId: the public ID string
1645 * @sysId: the system ID string
1646 *
1647 * Do a complete resolution lookup of an External Identifier
1648 *
1649 * Returns the URI of the resource or NULL if not found, it must be freed
1650 * by the caller.
1651 */
1652xmlChar *
1653xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
1654 if (xmlDefaultXMLCatalogList != NULL) {
1655 return(xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, sysID));
1656 } else {
1657 return(xmlCatalogSGMLResolve(pubID, sysID));
1658 }
1659}
1660
1661/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001662 * xmlCatalogDump:
1663 * @out: the file.
1664 *
1665 * Free up all the memory associated with catalogs
1666 */
1667void
1668xmlCatalogDump(FILE *out) {
1669 if (out == NULL)
1670 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00001671
1672 if (xmlDefaultXMLCatalogList != NULL) {
1673 xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList);
1674 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001675 xmlHashScan(xmlDefaultCatalog,
1676 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00001677 }
1678}
1679
1680/**
1681 * xmlCatalogAdd:
1682 * @type: the type of record to add to the catalog
1683 * @orig: the system, public or prefix to match
1684 * @replace: the replacement value for the match
1685 *
1686 * Add an entry in the catalog, it may overwrite existing but
1687 * different entries.
1688 *
1689 * Returns 0 if successful, -1 otherwise
1690 */
1691int
1692xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
1693 int res = -1;
1694
1695 if (xmlDefaultXMLCatalogList != NULL) {
1696 res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
1697 } else if (xmlDefaultCatalog != NULL) {
1698 xmlCatalogEntryType typ;
1699
Daniel Veillardcda96922001-08-21 10:56:31 +00001700 typ = xmlGetSGMLCatalogEntryType(type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001701 if (type != XML_CATA_NONE) {
1702 xmlCatalogEntryPtr entry;
1703 entry = xmlNewCatalogEntry(typ, orig, replace);
1704 res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
1705 }
1706 }
1707 return(res);
1708}
1709
1710/**
1711 * xmlCatalogRemove:
1712 * @value: the value to remove
1713 *
1714 * Remove an entry from the catalog
1715 *
1716 * Returns 0 if successful, -1 otherwise
1717 */
1718int
1719xmlCatalogRemove(const xmlChar *value) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001720 int res = -1;
1721
1722 if (xmlDefaultXMLCatalogList != NULL) {
1723 res = xmlDelXMLCatalog(xmlDefaultXMLCatalogList, value);
1724 } else if (xmlDefaultCatalog != NULL) {
1725 TODO
1726 }
1727 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00001728}
1729
1730/**
1731 * xmlCatalogSetDebug:
1732 * @level: the debug level of catalogs required
1733 *
1734 * Used to set the debug level for catalog operation, 0 disable
1735 * debugging, 1 enable it
1736 *
1737 * Returns the previous value of the catalog debugging level
1738 */
1739int
1740xmlCatalogSetDebug(int level) {
1741 int ret = xmlDebugCatalogs;
1742
1743 if (level <= 0)
1744 xmlDebugCatalogs = 0;
1745 else
1746 xmlDebugCatalogs = level;
1747 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00001748}
1749#endif /* LIBXML_CATALOG_ENABLED */