blob: a5e063199cd93fef868a1115d0dfadcc2b72a85c [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
48
Daniel Veillarda7374592001-05-10 14:17:55 +000049/************************************************************************
50 * *
51 * Types, all private *
52 * *
53 ************************************************************************/
54
55typedef enum {
Daniel Veillard344cee72001-08-20 00:08:40 +000056 XML_CATA_PREFER_PUBLIC = 1,
57 XML_CATA_PREFER_SYSTEM
58} xmlCatalogPrefer;
59
60typedef enum {
Daniel Veillarda7374592001-05-10 14:17:55 +000061 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000062 XML_CATA_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000063 XML_CATA_NEXT_CATALOG,
64 XML_CATA_PUBLIC,
65 XML_CATA_SYSTEM,
66 XML_CATA_REWRITE_SYSTEM,
67 XML_CATA_DELEGATE_PUBLIC,
68 XML_CATA_DELEGATE_SYSTEM,
69 XML_CATA_URI,
70 XML_CATA_REWRITE_URI,
71 XML_CATA_DELEGATE_URI,
72 SGML_CATA_SYSTEM,
73 SGML_CATA_PUBLIC,
74 SGML_CATA_ENTITY,
75 SGML_CATA_PENTITY,
76 SGML_CATA_DOCTYPE,
77 SGML_CATA_LINKTYPE,
78 SGML_CATA_NOTATION,
79 SGML_CATA_DELEGATE,
80 SGML_CATA_BASE,
81 SGML_CATA_CATALOG,
82 SGML_CATA_DOCUMENT,
83 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000084} xmlCatalogEntryType;
85
86typedef struct _xmlCatalogEntry xmlCatalogEntry;
87typedef xmlCatalogEntry *xmlCatalogEntryPtr;
88struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +000089 struct _xmlCatalogEntry *next;
90 struct _xmlCatalogEntry *parent;
91 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +000092 xmlCatalogEntryType type;
93 xmlChar *name;
94 xmlChar *value;
95};
96
97static xmlHashTablePtr xmlDefaultCatalog;
Daniel Veillard344cee72001-08-20 00:08:40 +000098static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +000099
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000100/* Catalog stack */
Daniel Veillard81418e32001-05-22 15:08:55 +0000101static const char * catalTab[10]; /* stack of catals */
102static int catalNr = 0; /* Number of current catal streams */
103static int catalMax = 10; /* Max number of catal streams */
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000104
Daniel Veillard344cee72001-08-20 00:08:40 +0000105static int xmlDebugCatalogs = 0; /* used for debugging */
106
Daniel Veillarda7374592001-05-10 14:17:55 +0000107/************************************************************************
108 * *
109 * alloc or dealloc *
110 * *
111 ************************************************************************/
112
113static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000114xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
115 const xmlChar *value) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000116 xmlCatalogEntryPtr ret;
117
118 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
119 if (ret == NULL) {
120 xmlGenericError(xmlGenericErrorContext,
121 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
122 return(NULL);
123 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000124 ret->next = NULL;
125 ret->parent = NULL;
126 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000127 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000128 if (name != NULL)
129 ret->name = xmlStrdup(name);
130 else
131 ret->name = NULL;
132 if (value != NULL)
133 ret->value = xmlStrdup(value);
134 else
135 ret->value = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000136 return(ret);
137}
138
139static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000140xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
141
142static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000143xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
144 if (ret == NULL)
145 return;
Daniel Veillard344cee72001-08-20 00:08:40 +0000146 if (ret->children != NULL)
147 xmlFreeCatalogEntryList(ret->children);
Daniel Veillarda7374592001-05-10 14:17:55 +0000148 if (ret->name != NULL)
149 xmlFree(ret->name);
150 if (ret->value != NULL)
151 xmlFree(ret->value);
152 xmlFree(ret);
153}
154
Daniel Veillard344cee72001-08-20 00:08:40 +0000155static void
156xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
157 xmlCatalogEntryPtr next;
158
159 while (ret != NULL) {
160 next = ret->next;
161 xmlFreeCatalogEntry(ret);
162 ret = next;
163 }
164}
165
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000166/**
167 * xmlCatalogDumpEntry:
168 * @entry: the
169 * @out: the file.
170 *
171 * Free up all the memory associated with catalogs
172 */
173static void
174xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
175 if ((entry == NULL) || (out == NULL))
176 return;
177 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000178 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000179 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000180 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000181 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000182 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000183 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000184 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000185 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000186 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000187 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000188 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000189 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000190 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000191 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000192 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000193 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000194 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000195 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000196 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000197 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000198 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000199 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000200 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000201 fprintf(out, "SGMLDECL "); break;
202 default:
203 return;
204 }
205 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000206 case SGML_CATA_ENTITY:
207 case SGML_CATA_PENTITY:
208 case SGML_CATA_DOCTYPE:
209 case SGML_CATA_LINKTYPE:
210 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000211 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000212 case SGML_CATA_PUBLIC:
213 case SGML_CATA_SYSTEM:
214 case SGML_CATA_SGMLDECL:
215 case SGML_CATA_DOCUMENT:
216 case SGML_CATA_CATALOG:
217 case SGML_CATA_BASE:
218 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000219 fprintf(out, "\"%s\"", entry->name); break;
220 default:
221 break;
222 }
223 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000224 case SGML_CATA_ENTITY:
225 case SGML_CATA_PENTITY:
226 case SGML_CATA_DOCTYPE:
227 case SGML_CATA_LINKTYPE:
228 case SGML_CATA_NOTATION:
229 case SGML_CATA_PUBLIC:
230 case SGML_CATA_SYSTEM:
231 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000232 fprintf(out, " \"%s\"", entry->value); break;
233 default:
234 break;
235 }
236 fprintf(out, "\n");
237}
238
Daniel Veillarda7374592001-05-10 14:17:55 +0000239/************************************************************************
240 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000241 * The XML Catalog parser *
242 * *
243 ************************************************************************/
244
245static xmlCatalogEntryPtr
246xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
247
248static xmlCatalogEntryPtr
249xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
250 const char *file);
251static void
252xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
253 xmlCatalogEntryPtr parent);
254
255static xmlCatalogEntryType
256xmlGetXMLCatalogEntryType(const xmlChar *name) {
257 xmlCatalogEntryType type = XML_CATA_NONE;
258 if (xmlStrEqual(name, (const xmlChar *) "system"))
259 type = XML_CATA_SYSTEM;
260 else if (xmlStrEqual(name, (const xmlChar *) "public"))
261 type = XML_CATA_PUBLIC;
262 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
263 type = XML_CATA_REWRITE_SYSTEM;
264 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
265 type = XML_CATA_DELEGATE_PUBLIC;
266 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
267 type = XML_CATA_DELEGATE_SYSTEM;
268 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
269 type = XML_CATA_URI;
270 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
271 type = XML_CATA_REWRITE_URI;
272 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
273 type = XML_CATA_DELEGATE_URI;
274 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
275 type = XML_CATA_NEXT_CATALOG;
276 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
277 type = XML_CATA_CATALOG;
278 return(type);
279}
280
281static xmlCatalogEntryPtr
282xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
283 const xmlChar *name, const xmlChar *attrName,
284 const xmlChar *uriAttrName) {
285 int ok = 1;
286 xmlChar *uriValue;
287 xmlChar *nameValue = NULL;
288 xmlChar *base = NULL;
289 xmlChar *URL = NULL;
290 xmlCatalogEntryPtr ret = NULL;
291
292 if (attrName != NULL) {
293 nameValue = xmlGetProp(cur, attrName);
294 if (nameValue == NULL) {
295 xmlGenericError(xmlGenericErrorContext,
296 "%s entry lacks '%s'\n", name, attrName);
297 ok = 0;
298 }
299 }
300 uriValue = xmlGetProp(cur, uriAttrName);
301 if (uriValue == NULL) {
302 xmlGenericError(xmlGenericErrorContext,
303 "%s entry lacks '%s'\n", name, uriAttrName);
304 ok = 0;
305 }
306 if (!ok) {
307 if (nameValue != NULL)
308 xmlFree(nameValue);
309 if (uriValue != NULL)
310 xmlFree(uriValue);
311 return(NULL);
312 }
313
314 base = xmlNodeGetBase(cur->doc, cur);
315 URL = xmlBuildURI(uriValue, base);
316 if (URL != NULL) {
317 if (xmlDebugCatalogs) {
318 if (nameValue != NULL)
319 printf("Found %s: '%s' '%s'\n", name, nameValue, URL);
320 else
321 printf("Found %s: '%s'\n", name, URL);
322 }
323 ret = xmlNewCatalogEntry(type, nameValue, URL);
324 } else {
325 xmlGenericError(xmlGenericErrorContext,
326 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
327 }
328 if (nameValue != NULL)
329 xmlFree(nameValue);
330 if (uriValue != NULL)
331 xmlFree(uriValue);
332 if (base != NULL)
333 xmlFree(base);
334 if (URL != NULL)
335 xmlFree(URL);
336 return(ret);
337}
338
339static void
340xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
341 xmlCatalogEntryPtr parent)
342{
343 xmlChar *uri = NULL;
344 xmlChar *URL = NULL;
345 xmlChar *base = NULL;
346 xmlCatalogEntryPtr entry = NULL;
347
348 if (cur == NULL)
349 return;
350 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
351 xmlChar *prop;
352
353 prop = xmlGetProp(cur, BAD_CAST "prefer");
354 if (prop != NULL) {
355 if (xmlStrEqual(prop, BAD_CAST "system")) {
356 prefer = XML_CATA_PREFER_SYSTEM;
357 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
358 prefer = XML_CATA_PREFER_PUBLIC;
359 } else {
360 xmlGenericError(xmlGenericErrorContext,
361 "Invalid value for prefer: '%s'\n", prop);
362 }
363 xmlFree(prop);
364 }
365 /*
366 * Recurse to propagate prefer to the subtree
367 * (xml:base handling is automated)
368 */
369 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
370 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
371 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
372 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri");
373 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
374 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
375 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri");
376 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
377 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
378 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
379 BAD_CAST "rewritePrefix");
380 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
381 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
382 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
383 BAD_CAST "catalog");
384 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
385 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
386 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
387 BAD_CAST "catalog");
388 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
389 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
390 BAD_CAST "uri", BAD_CAST "name",
391 BAD_CAST "uri");
392 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
393 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
394 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
395 BAD_CAST "rewritePrefix");
396 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
397 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
398 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
399 BAD_CAST "catalog");
400 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
401 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
402 BAD_CAST "nextCatalog", NULL,
403 BAD_CAST "catalog");
404 }
405 if ((entry != NULL) && (parent != NULL)) {
406 entry->parent = parent;
407 if (parent->children == NULL)
408 parent->children = entry;
409 else {
410 xmlCatalogEntryPtr prev;
411
412 prev = parent->children;
413 while (prev->next != NULL)
414 prev = prev->next;
415 prev->next = entry;
416 }
417 }
418 if (base != NULL)
419 xmlFree(base);
420 if (uri != NULL)
421 xmlFree(uri);
422 if (URL != NULL)
423 xmlFree(URL);
424}
425
426static void
427xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
428 xmlCatalogEntryPtr parent) {
429 while (cur != NULL) {
430 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
431 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
432 xmlParseXMLCatalogNode(cur, prefer, parent);
433 }
434 cur = cur->next;
435 }
436 /* TODO: sort the list according to REWRITE lengths and prefer value */
437}
438
439static xmlCatalogEntryPtr
440xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
441 const char *file) {
442 xmlDocPtr doc;
443 xmlNodePtr cur;
444 xmlChar *prop;
445 xmlCatalogEntryPtr parent = NULL;
446
447 if ((value == NULL) || (file == NULL))
448 return(NULL);
449
450 doc = xmlParseDoc((xmlChar *) value);
451 if (doc == NULL)
452 return(NULL);
453 doc->URL = xmlStrdup((const xmlChar *) file);
454
455 cur = xmlDocGetRootElement(doc);
456 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
457 (cur->ns != NULL) && (cur->ns->href != NULL) &&
458 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
459
460 parent = xmlNewCatalogEntry(XML_CATA_CATALOG,
461 (const xmlChar *)file, NULL);
462 if (parent == NULL) {
463 xmlFreeDoc(doc);
464 return(NULL);
465 }
466
467 prop = xmlGetProp(cur, BAD_CAST "prefer");
468 if (prop != NULL) {
469 if (xmlStrEqual(prop, BAD_CAST "system")) {
470 prefer = XML_CATA_PREFER_SYSTEM;
471 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
472 prefer = XML_CATA_PREFER_PUBLIC;
473 } else {
474 xmlGenericError(xmlGenericErrorContext,
475 "Invalid value for prefer: '%s'\n",
476 prop);
477 }
478 xmlFree(prop);
479 }
480 cur = cur->children;
481 xmlParseXMLCatalogNodeList(cur, prefer, parent);
482 } else {
483 xmlGenericError(xmlGenericErrorContext,
484 "File %s is not an XML Catalog\n", file);
485 xmlFreeDoc(doc);
486 return(NULL);
487 }
488 xmlFreeDoc(doc);
489 return(parent);
490}
491
492static xmlCatalogEntryPtr
493xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
494 xmlDocPtr doc;
495 xmlNodePtr cur;
496 xmlChar *prop;
497 xmlCatalogEntryPtr parent = NULL;
498
499 if (filename == NULL)
500 return(NULL);
501
502 doc = xmlParseFile((const char *) filename);
503 if (doc == NULL)
504 return(NULL);
505
506 cur = xmlDocGetRootElement(doc);
507 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
508 (cur->ns != NULL) && (cur->ns->href != NULL) &&
509 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
510
511 parent = xmlNewCatalogEntry(XML_CATA_CATALOG,
512 (const xmlChar *)filename, NULL);
513 if (parent == NULL) {
514 xmlFreeDoc(doc);
515 return(NULL);
516 }
517
518 prop = xmlGetProp(cur, BAD_CAST "prefer");
519 if (prop != NULL) {
520 if (xmlStrEqual(prop, BAD_CAST "system")) {
521 prefer = XML_CATA_PREFER_SYSTEM;
522 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
523 prefer = XML_CATA_PREFER_PUBLIC;
524 } else {
525 xmlGenericError(xmlGenericErrorContext,
526 "Invalid value for prefer: '%s'\n",
527 prop);
528 }
529 xmlFree(prop);
530 }
531 cur = cur->children;
532 xmlParseXMLCatalogNodeList(cur, prefer, parent);
533 } else {
534 xmlGenericError(xmlGenericErrorContext,
535 "File %s is not an XML Catalog\n", filename);
536 xmlFreeDoc(doc);
537 return(NULL);
538 }
539 xmlFreeDoc(doc);
540 return(parent);
541}
542
543static int
544xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
545 int ret;
546 xmlDocPtr doc;
547 xmlNsPtr ns;
548 xmlDtdPtr dtd;
549 xmlNodePtr node, catalog;
550 xmlOutputBufferPtr buf;
551 xmlCatalogEntryPtr cur;
552
553 /*
554 * Rebuild a catalog
555 */
556 doc = xmlNewDoc(NULL);
557 if (doc == NULL)
558 return(-1);
559 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
560 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
561BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
562
563 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
564
565 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
566 if (ns == NULL) {
567 xmlFreeDoc(doc);
568 return(-1);
569 }
570 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
571 if (catalog == NULL) {
572 xmlFreeNs(ns);
573 xmlFreeDoc(doc);
574 return(-1);
575 }
576 catalog->nsDef = ns;
577 xmlAddChild((xmlNodePtr) doc, catalog);
578
579 /*
580 * add all the catalog entries
581 */
582 cur = catal;
583 while (cur != NULL) {
584 switch (cur->type) {
585 case XML_CATA_CATALOG:
586 if (cur == catal) {
587 cur = cur->children;
588 continue;
589 }
590 break;
591 case XML_CATA_NEXT_CATALOG:
592 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
593 xmlSetProp(node, BAD_CAST "catalog", cur->value);
594 xmlAddChild(catalog, node);
595 break;
596 case XML_CATA_NONE:
597 break;
598 case XML_CATA_PUBLIC:
599 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
600 xmlSetProp(node, BAD_CAST "publicId", cur->name);
601 xmlSetProp(node, BAD_CAST "uri", cur->value);
602 xmlAddChild(catalog, node);
603 break;
604 case XML_CATA_SYSTEM:
605 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
606 xmlSetProp(node, BAD_CAST "systemId", cur->name);
607 xmlSetProp(node, BAD_CAST "uri", cur->value);
608 xmlAddChild(catalog, node);
609 break;
610 case XML_CATA_REWRITE_SYSTEM:
611 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
612 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
613 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
614 xmlAddChild(catalog, node);
615 break;
616 case XML_CATA_DELEGATE_PUBLIC:
617 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
618 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
619 xmlSetProp(node, BAD_CAST "catalog", cur->value);
620 xmlAddChild(catalog, node);
621 break;
622 case XML_CATA_DELEGATE_SYSTEM:
623 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
624 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
625 xmlSetProp(node, BAD_CAST "catalog", cur->value);
626 xmlAddChild(catalog, node);
627 break;
628 case XML_CATA_URI:
629 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
630 xmlSetProp(node, BAD_CAST "name", cur->name);
631 xmlSetProp(node, BAD_CAST "uri", cur->value);
632 xmlAddChild(catalog, node);
633 break;
634 case XML_CATA_REWRITE_URI:
635 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
636 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
637 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
638 xmlAddChild(catalog, node);
639 break;
640 case XML_CATA_DELEGATE_URI:
641 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
642 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
643 xmlSetProp(node, BAD_CAST "catalog", cur->value);
644 xmlAddChild(catalog, node);
645 break;
646 case SGML_CATA_SYSTEM:
647 case SGML_CATA_PUBLIC:
648 case SGML_CATA_ENTITY:
649 case SGML_CATA_PENTITY:
650 case SGML_CATA_DOCTYPE:
651 case SGML_CATA_LINKTYPE:
652 case SGML_CATA_NOTATION:
653 case SGML_CATA_DELEGATE:
654 case SGML_CATA_BASE:
655 case SGML_CATA_CATALOG:
656 case SGML_CATA_DOCUMENT:
657 case SGML_CATA_SGMLDECL:
658 break;
659 }
660 cur = cur->next;
661 }
662
663 /*
664 * reserialize it
665 */
666 buf = xmlOutputBufferCreateFile(out, NULL);
667 if (buf == NULL) {
668 xmlFreeDoc(doc);
669 return(-1);
670 }
671 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
672
673 /*
674 * Free it
675 */
676 xmlFreeDoc(doc);
677
678 return(ret);
679}
680
681/**
682 * xmlAddXMLCatalog:
683 * @catal: top of an XML catalog
684 * @type: the type of record to add to the catalog
685 * @orig: the system, public or prefix to match
686 * @replace: the replacement value for the match
687 *
688 * Add an entry in the XML catalog, it may overwrite existing but
689 * different entries.
690 *
691 * Returns 0 if successful, -1 otherwise
692 */
693static int
694xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
695 const xmlChar *orig, const xmlChar *replace) {
696 xmlCatalogEntryPtr cur;
697 xmlCatalogEntryType typ;
698
699 if ((catal == NULL) || (catal->type != XML_CATA_CATALOG))
700 return(-1);
701 typ = xmlGetXMLCatalogEntryType(type);
702 if (typ == XML_CATA_NONE)
703 return(-1);
704
705 cur = catal->children;
706 /*
707 * Might be a simple "update in place"
708 */
709 if (cur != NULL) {
710 while (cur != NULL) {
711 cur = cur->next;
712 if ((cur->type == typ) && (xmlStrEqual(orig, cur->name))) {
713 if (cur->value != NULL)
714 xmlFree(cur->value);
715 cur->value = xmlStrdup(replace);
716 return(1);
717 }
718 if (cur->next == NULL)
719 break;
720 cur = cur->next;
721 }
722 }
723 if (cur == NULL)
724 catal->children = xmlNewCatalogEntry(typ, orig, replace);
725 else
726 cur->next = xmlNewCatalogEntry(typ, orig, replace);
727 return(1);
728}
729
730/************************************************************************
731 * *
732 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +0000733 * *
734 ************************************************************************/
735
736
737#define RAW *cur
738#define NEXT cur++;
739#define SKIP(x) cur += x;
740
741#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
742
743static const xmlChar *
744xmlParseCatalogComment(const xmlChar *cur) {
745 if ((cur[0] != '-') || (cur[1] != '-'))
746 return(cur);
747 SKIP(2);
748 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
749 NEXT;
750 if (cur[0] == 0) {
751 return(NULL);
752 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000753 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +0000754}
755
756static const xmlChar *
757xmlParseCatalogPubid(const xmlChar *cur, xmlChar **id) {
758 xmlChar *buf = NULL;
759 int len = 0;
760 int size = 50;
761 xmlChar stop;
762 int count = 0;
763
764 *id = NULL;
765
766 if (RAW == '"') {
767 NEXT;
768 stop = '"';
769 } else if (RAW == '\'') {
770 NEXT;
771 stop = '\'';
772 } else {
773 stop = ' ';
774 }
775 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
776 if (buf == NULL) {
777 xmlGenericError(xmlGenericErrorContext,
778 "malloc of %d byte failed\n", size);
779 return(NULL);
780 }
781 while (xmlIsPubidChar(*cur)) {
782 if ((*cur == stop) && (stop != ' '))
783 break;
784 if ((stop == ' ') && (IS_BLANK(*cur)))
785 break;
786 if (len + 1 >= size) {
787 size *= 2;
788 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
789 if (buf == NULL) {
790 xmlGenericError(xmlGenericErrorContext,
791 "realloc of %d byte failed\n", size);
792 return(NULL);
793 }
794 }
795 buf[len++] = *cur;
796 count++;
797 NEXT;
798 }
799 buf[len] = 0;
800 if (stop == ' ') {
801 if (!IS_BLANK(*cur)) {
802 xmlFree(buf);
803 return(NULL);
804 }
805 } else {
806 if (*cur != stop) {
807 xmlFree(buf);
808 return(NULL);
809 }
810 NEXT;
811 }
812 *id = buf;
813 return(cur);
814}
815
816static const xmlChar *
817xmlParseCatalogName(const xmlChar *cur, xmlChar **name) {
818 xmlChar buf[XML_MAX_NAMELEN + 5];
819 int len = 0;
820 int c;
821
822 *name = NULL;
823
824 /*
825 * Handler for more complex cases
826 */
827 c = *cur;
828 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
829 return(NULL);
830 }
831
832 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
833 (c == '.') || (c == '-') ||
834 (c == '_') || (c == ':'))) {
835 buf[len++] = c;
836 cur++;
837 c = *cur;
838 if (len >= XML_MAX_NAMELEN)
839 return(NULL);
840 }
841 *name = xmlStrndup(buf, len);
842 return(cur);
843}
844
Daniel Veillard344cee72001-08-20 00:08:40 +0000845static xmlCatalogEntryType
846xmlGetCatalogEntryType(const xmlChar *name) {
847 xmlCatalogEntryType type = XML_CATA_NONE;
848 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
849 type = SGML_CATA_SYSTEM;
850 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
851 type = SGML_CATA_PUBLIC;
852 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
853 type = SGML_CATA_DELEGATE;
854 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
855 type = SGML_CATA_ENTITY;
856 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
857 type = SGML_CATA_DOCTYPE;
858 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
859 type = SGML_CATA_LINKTYPE;
860 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
861 type = SGML_CATA_NOTATION;
862 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
863 type = SGML_CATA_SGMLDECL;
864 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
865 type = SGML_CATA_DOCUMENT;
866 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
867 type = SGML_CATA_CATALOG;
868 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
869 type = SGML_CATA_BASE;
870 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
871 type = SGML_CATA_DELEGATE;
872 return(type);
873}
874
Daniel Veillarda7374592001-05-10 14:17:55 +0000875static int
876xmlParseCatalog(const xmlChar *value, const char *file) {
877 const xmlChar *cur = value;
878 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000879 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +0000880
881 if ((cur == NULL) || (file == NULL))
882 return(-1);
883 base = xmlStrdup((const xmlChar *) file);
884
885 while ((cur != NULL) && (cur[0] != '0')) {
886 SKIP_BLANKS;
887 if ((cur[0] == '-') && (cur[1] == '-')) {
888 cur = xmlParseCatalogComment(cur);
889 if (cur == NULL) {
890 /* error */
891 break;
892 }
893 } else {
894 xmlChar *sysid = NULL;
895 xmlChar *name = NULL;
896 xmlCatalogEntryType type = XML_CATA_NONE;
897
898 cur = xmlParseCatalogName(cur, &name);
899 if (name == NULL) {
900 /* error */
901 break;
902 }
903 if (!IS_BLANK(*cur)) {
904 /* error */
905 break;
906 }
907 SKIP_BLANKS;
908 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000909 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +0000910 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000911 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +0000912 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000913 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +0000914 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000915 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +0000916 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000917 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +0000918 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000919 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +0000920 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000921 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +0000922 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000923 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000924 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000925 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +0000926 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000927 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +0000928 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000929 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +0000930 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +0000931 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +0000932 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
933 xmlFree(name);
934 cur = xmlParseCatalogName(cur, &name);
935 if (name == NULL) {
936 /* error */
937 break;
938 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000939 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +0000940 continue;
941 }
942 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000943 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000944
945 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000946 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +0000947 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +0000948 type = SGML_CATA_PENTITY;
949 case SGML_CATA_PENTITY:
950 case SGML_CATA_DOCTYPE:
951 case SGML_CATA_LINKTYPE:
952 case SGML_CATA_NOTATION:
Daniel Veillarda7374592001-05-10 14:17:55 +0000953 cur = xmlParseCatalogName(cur, &name);
954 if (cur == NULL) {
955 /* error */
956 break;
957 }
958 if (!IS_BLANK(*cur)) {
959 /* error */
960 break;
961 }
962 SKIP_BLANKS;
963 cur = xmlParseCatalogPubid(cur, &sysid);
964 if (cur == NULL) {
965 /* error */
966 break;
967 }
968 break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000969 case SGML_CATA_PUBLIC:
970 case SGML_CATA_SYSTEM:
971 case SGML_CATA_DELEGATE:
Daniel Veillarda7374592001-05-10 14:17:55 +0000972 cur = xmlParseCatalogPubid(cur, &name);
973 if (cur == NULL) {
974 /* error */
975 break;
976 }
977 if (!IS_BLANK(*cur)) {
978 /* error */
979 break;
980 }
981 SKIP_BLANKS;
982 cur = xmlParseCatalogPubid(cur, &sysid);
983 if (cur == NULL) {
984 /* error */
985 break;
986 }
987 break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000988 case SGML_CATA_BASE:
989 case SGML_CATA_CATALOG:
990 case SGML_CATA_DOCUMENT:
991 case SGML_CATA_SGMLDECL:
Daniel Veillarda7374592001-05-10 14:17:55 +0000992 cur = xmlParseCatalogPubid(cur, &sysid);
993 if (cur == NULL) {
994 /* error */
995 break;
996 }
997 break;
998 default:
999 break;
1000 }
1001 if (cur == NULL) {
1002 if (name != NULL)
1003 xmlFree(name);
1004 if (sysid != NULL)
1005 xmlFree(sysid);
1006 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001007 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001008 if (base != NULL)
1009 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001010 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00001011 } else if ((type == SGML_CATA_PUBLIC) ||
1012 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001013 xmlChar *filename;
1014
1015 filename = xmlBuildURI(sysid, base);
1016 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001017 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00001018
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001019 entry = xmlNewCatalogEntry(type, name, filename);
1020 res = xmlHashAddEntry(xmlDefaultCatalog, name, entry);
1021 if (res < 0) {
1022 xmlFreeCatalogEntry(entry);
1023 }
1024 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00001025 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001026
Daniel Veillard344cee72001-08-20 00:08:40 +00001027 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001028 xmlChar *filename;
1029
1030 filename = xmlBuildURI(sysid, base);
1031 if (filename != NULL) {
1032 xmlLoadCatalog((const char *)filename);
1033 xmlFree(filename);
1034 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001035 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001036 /*
1037 * drop anything else we won't handle it
1038 */
1039 if (name != NULL)
1040 xmlFree(name);
1041 if (sysid != NULL)
1042 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001043 }
1044 }
1045 if (base != NULL)
1046 xmlFree(base);
1047 if (cur == NULL)
1048 return(-1);
1049 return(0);
1050}
1051
1052/************************************************************************
1053 * *
1054 * Public interfaces *
1055 * *
1056 ************************************************************************/
1057
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001058/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001059 * xmlLoadCatalog:
1060 * @filename: a file path
1061 *
Daniel Veillard81418e32001-05-22 15:08:55 +00001062 * Load the catalog and makes its definitions effective for the default
1063 * external entity loader. It will recuse in CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001064 * TODO: this function is not thread safe, catalog initialization should
1065 * be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00001066 *
1067 * Returns 0 in case of success -1 in case of error
1068 */
1069int
1070xmlLoadCatalog(const char *filename) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001071 int fd, len, ret, i;
Daniel Veillarda7374592001-05-10 14:17:55 +00001072 struct stat info;
1073 xmlChar *content;
1074
1075 if (filename == NULL)
1076 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001077
Daniel Veillarda7374592001-05-10 14:17:55 +00001078 if (xmlDefaultCatalog == NULL)
1079 xmlDefaultCatalog = xmlHashCreate(20);
1080 if (xmlDefaultCatalog == NULL)
1081 return(-1);
1082
1083 if (stat(filename, &info) < 0)
1084 return(-1);
1085
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001086 /*
1087 * Prevent loops
1088 */
1089 for (i = 0;i < catalNr;i++) {
Daniel Veillard81418e32001-05-22 15:08:55 +00001090 if (xmlStrEqual((const xmlChar *)catalTab[i],
1091 (const xmlChar *)filename)) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001092 xmlGenericError(xmlGenericErrorContext,
1093 "xmlLoadCatalog: %s seems to induce a loop\n",
1094 filename);
1095 return(-1);
1096 }
1097 }
1098 if (catalNr >= catalMax) {
1099 xmlGenericError(xmlGenericErrorContext,
1100 "xmlLoadCatalog: %s catalog list too deep\n",
1101 filename);
1102 return(-1);
1103 }
1104 catalTab[catalNr++] = filename;
1105
1106 if ((fd = open(filename, O_RDONLY)) < 0) {
1107 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001108 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001109 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001110
1111 content = xmlMalloc(info.st_size + 10);
1112 if (content == NULL) {
1113 xmlGenericError(xmlGenericErrorContext,
1114 "realloc of %d byte failed\n", info.st_size + 10);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001115 catalNr--;
1116 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00001117 }
1118 len = read(fd, content, info.st_size);
1119 if (len < 0) {
1120 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001121 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001122 return(-1);
1123 }
1124 content[len] = 0;
1125 close(fd);
1126
Daniel Veillard344cee72001-08-20 00:08:40 +00001127 if ((content[0] == ' ') || (content[0] == '-') ||
1128 ((content[0] >= 'A') && (content[0] <= 'Z')) ||
1129 ((content[0] >= 'a') && (content[0] <= 'z')))
1130 ret = xmlParseCatalog(content, filename);
1131 else {
1132 xmlCatalogEntryPtr catal, tmp;
1133 /* TODO: allow to switch the default preference */
1134 catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
1135 if (catal != NULL) {
1136 if (xmlDefaultXMLCatalogList == NULL)
1137 xmlDefaultXMLCatalogList = catal;
1138 else {
1139 tmp = xmlDefaultXMLCatalogList;
1140 while (tmp->next != NULL)
1141 tmp = tmp->next;
1142 tmp->next = catal;
1143 }
1144 ret = 0;
1145 } else
1146 ret = -1;
1147 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001148 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001149 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001150 return(ret);
1151}
1152
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001153/**
Daniel Veillard81418e32001-05-22 15:08:55 +00001154 * xmlLoadCatalogs:
1155 * @paths: a list of file path separated by ':' or spaces
1156 *
1157 * Load the catalogs and makes their definitions effective for the default
1158 * external entity loader.
1159 * TODO: this function is not thread safe, catalog initialization should
1160 * be done once at startup
1161 */
1162void
1163xmlLoadCatalogs(const char *pathss) {
1164 const char *cur;
1165 const char *paths;
1166 xmlChar *path;
1167
1168 cur = pathss;
1169 while ((cur != NULL) && (*cur != 0)) {
1170 while (IS_BLANK(*cur)) cur++;
1171 if (*cur != 0) {
1172 paths = cur;
1173 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
1174 cur++;
1175 path = xmlStrndup((const xmlChar *)paths, cur - paths);
1176 if (path != NULL) {
1177 xmlLoadCatalog((const char *) path);
1178 xmlFree(path);
1179 }
1180 }
1181 while (*cur == ':')
1182 cur++;
1183 }
1184}
1185
Daniel Veillarda7374592001-05-10 14:17:55 +00001186/**
1187 * xmlCatalogCleanup:
1188 *
1189 * Free up all the memory associated with catalogs
1190 */
1191void
1192xmlCatalogCleanup(void) {
1193 if (xmlDefaultCatalog != NULL)
1194 xmlHashFree(xmlDefaultCatalog,
1195 (xmlHashDeallocator) xmlFreeCatalogEntry);
1196 xmlDefaultCatalog = NULL;
1197}
1198
1199/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001200 * xmlCatalogGetSystem:
1201 * @sysId: the system ID string
Daniel Veillarda7374592001-05-10 14:17:55 +00001202 *
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001203 * Try to lookup the resource associated to a system ID
1204 *
1205 * Returns the resource name if found or NULL otherwise.
Daniel Veillarda7374592001-05-10 14:17:55 +00001206 */
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001207const xmlChar *
1208xmlCatalogGetSystem(const xmlChar *sysID) {
1209 xmlCatalogEntryPtr entry;
1210
1211 if ((sysID == NULL) || (xmlDefaultCatalog == NULL))
1212 return(NULL);
1213 entry = (xmlCatalogEntryPtr) xmlHashLookup(xmlDefaultCatalog, sysID);
1214 if (entry == NULL)
1215 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001216 if (entry->type == SGML_CATA_SYSTEM)
1217 return(entry->value);
1218 return(NULL);
1219}
1220
1221/**
1222 * xmlCatalogGetXMLPublic:
1223 * @catal: an XML catalog
1224 * @pubId: the public ID string
1225 *
1226 * Try to lookup the system ID associated to a public ID
1227 *
1228 * Returns the system ID if found or NULL otherwise.
1229 */
1230const xmlChar *
1231xmlCatalogGetXMLPublic(xmlCatalogEntryPtr catal, const xmlChar *pubID) {
1232 const xmlChar *ret;
1233 while (catal != NULL) {
1234 switch (catal->type) {
1235 case XML_CATA_CATALOG:
1236 if (catal->children == NULL) {
1237 TODO /* fetch and fill */
1238 }
1239 ret = xmlCatalogGetXMLPublic(catal->children, pubID);
1240 if (ret != NULL)
1241 return(ret);
1242 break;
1243 case XML_CATA_NEXT_CATALOG:
1244 if (catal->children == NULL) {
1245 TODO /* fetch and fill */
1246 }
1247 case XML_CATA_PUBLIC:
1248 if (xmlStrEqual(pubID, catal->name))
1249 return(catal->value);
1250 break;
1251 case XML_CATA_SYSTEM:
1252 case XML_CATA_REWRITE_SYSTEM:
1253 case XML_CATA_DELEGATE_PUBLIC:
1254 case XML_CATA_DELEGATE_SYSTEM:
1255 case XML_CATA_URI:
1256 case XML_CATA_REWRITE_URI:
1257 case XML_CATA_DELEGATE_URI:
1258 TODO;
1259 break;
1260
1261 case XML_CATA_NONE:
1262 case SGML_CATA_SYSTEM:
1263 case SGML_CATA_PUBLIC:
1264 case SGML_CATA_ENTITY:
1265 case SGML_CATA_PENTITY:
1266 case SGML_CATA_DOCTYPE:
1267 case SGML_CATA_LINKTYPE:
1268 case SGML_CATA_NOTATION:
1269 case SGML_CATA_DELEGATE:
1270 case SGML_CATA_BASE:
1271 case SGML_CATA_CATALOG:
1272 case SGML_CATA_DOCUMENT:
1273 case SGML_CATA_SGMLDECL:
1274 /* Ignored entries */
1275 break;
1276 }
1277 catal = catal->next;
1278 }
1279 return(NULL);
1280}
1281
1282/**
1283 * xmlCatalogGetSGMLPublic:
1284 * @catal: an SGML catalog hash
1285 * @pubId: the public ID string
1286 *
1287 * Try to lookup the system ID associated to a public ID
1288 *
1289 * Returns the system ID if found or NULL otherwise.
1290 */
1291static const xmlChar *
1292xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
1293 xmlCatalogEntryPtr entry;
1294
1295 if (catal == NULL)
1296 return(NULL);
1297
1298 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
1299 if (entry == NULL)
1300 return(NULL);
1301 if (entry->type == SGML_CATA_PUBLIC)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001302 return(entry->value);
1303 return(NULL);
Daniel Veillarda7374592001-05-10 14:17:55 +00001304}
1305
1306/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001307 * xmlCatalogGetPublic:
1308 * @pubId: the public ID string
1309 *
1310 * Try to lookup the system ID associated to a public ID
1311 *
1312 * Returns the system ID if found or NULL otherwise.
1313 */
1314const xmlChar *
1315xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001316 xmlCatalogEntryPtr catal;
1317 const xmlChar *ret;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001318
Daniel Veillard344cee72001-08-20 00:08:40 +00001319 if (pubID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001320 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001321
1322 /*
1323 * Check first the XML catalogs
1324 */
1325 catal = xmlDefaultXMLCatalogList;
1326 if (catal != NULL) {
1327 ret = xmlCatalogGetXMLPublic(catal, pubID);
1328 if (ret != NULL)
1329 return(ret);
1330 }
1331
1332 if (xmlDefaultCatalog != NULL)
1333 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001334 return(NULL);
1335}
Daniel Veillard344cee72001-08-20 00:08:40 +00001336
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001337/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001338 * xmlCatalogDump:
1339 * @out: the file.
1340 *
1341 * Free up all the memory associated with catalogs
1342 */
1343void
1344xmlCatalogDump(FILE *out) {
1345 if (out == NULL)
1346 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00001347
1348 if (xmlDefaultXMLCatalogList != NULL) {
1349 xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList);
1350 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001351 xmlHashScan(xmlDefaultCatalog,
1352 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00001353 }
1354}
1355
1356/**
1357 * xmlCatalogAdd:
1358 * @type: the type of record to add to the catalog
1359 * @orig: the system, public or prefix to match
1360 * @replace: the replacement value for the match
1361 *
1362 * Add an entry in the catalog, it may overwrite existing but
1363 * different entries.
1364 *
1365 * Returns 0 if successful, -1 otherwise
1366 */
1367int
1368xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
1369 int res = -1;
1370
1371 if (xmlDefaultXMLCatalogList != NULL) {
1372 res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
1373 } else if (xmlDefaultCatalog != NULL) {
1374 xmlCatalogEntryType typ;
1375
1376 typ = xmlGetCatalogEntryType(type);
1377 if (type != XML_CATA_NONE) {
1378 xmlCatalogEntryPtr entry;
1379 entry = xmlNewCatalogEntry(typ, orig, replace);
1380 res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
1381 }
1382 }
1383 return(res);
1384}
1385
1386/**
1387 * xmlCatalogRemove:
1388 * @value: the value to remove
1389 *
1390 * Remove an entry from the catalog
1391 *
1392 * Returns 0 if successful, -1 otherwise
1393 */
1394int
1395xmlCatalogRemove(const xmlChar *value) {
1396}
1397
1398/**
1399 * xmlCatalogSetDebug:
1400 * @level: the debug level of catalogs required
1401 *
1402 * Used to set the debug level for catalog operation, 0 disable
1403 * debugging, 1 enable it
1404 *
1405 * Returns the previous value of the catalog debugging level
1406 */
1407int
1408xmlCatalogSetDebug(int level) {
1409 int ret = xmlDebugCatalogs;
1410
1411 if (level <= 0)
1412 xmlDebugCatalogs = 0;
1413 else
1414 xmlDebugCatalogs = level;
1415 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00001416}
1417#endif /* LIBXML_CATALOG_ENABLED */