blob: eaaf0754345a87e1f1631534c9a7bce195808acf [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
Daniel Veillardc0631a62001-09-20 13:56:06 +000030#ifdef HAVE_STDLIB_H
31#include <stdlib.h>
32#endif
Daniel Veillarda7374592001-05-10 14:17:55 +000033#include <string.h>
34#include <libxml/xmlmemory.h>
35#include <libxml/hash.h>
36#include <libxml/uri.h>
37#include <libxml/parserInternals.h>
38#include <libxml/catalog.h>
39#include <libxml/xmlerror.h>
40
Daniel Veillard6990bf32001-08-23 21:17:48 +000041#define MAX_DELEGATE 50
42
Daniel Veillard344cee72001-08-20 00:08:40 +000043/**
44 * TODO:
45 *
46 * macro to flag unimplemented blocks
47 */
48#define TODO \
49 xmlGenericError(xmlGenericErrorContext, \
50 "Unimplemented block at %s:%d\n", \
51 __FILE__, __LINE__);
52
Daniel Veillardcda96922001-08-21 10:56:31 +000053#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000054#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000055#ifndef XML_DEFAULT_CATALOG
Daniel Veillarde2940dd2001-08-22 00:06:49 +000056#define XML_DEFAULT_CATALOG "/etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000057#endif
Daniel Veillard344cee72001-08-20 00:08:40 +000058
Daniel Veillarda7374592001-05-10 14:17:55 +000059/************************************************************************
60 * *
61 * Types, all private *
62 * *
63 ************************************************************************/
64
65typedef enum {
66 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000067 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000068 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000069 XML_CATA_NEXT_CATALOG,
70 XML_CATA_PUBLIC,
71 XML_CATA_SYSTEM,
72 XML_CATA_REWRITE_SYSTEM,
73 XML_CATA_DELEGATE_PUBLIC,
74 XML_CATA_DELEGATE_SYSTEM,
75 XML_CATA_URI,
76 XML_CATA_REWRITE_URI,
77 XML_CATA_DELEGATE_URI,
78 SGML_CATA_SYSTEM,
79 SGML_CATA_PUBLIC,
80 SGML_CATA_ENTITY,
81 SGML_CATA_PENTITY,
82 SGML_CATA_DOCTYPE,
83 SGML_CATA_LINKTYPE,
84 SGML_CATA_NOTATION,
85 SGML_CATA_DELEGATE,
86 SGML_CATA_BASE,
87 SGML_CATA_CATALOG,
88 SGML_CATA_DOCUMENT,
89 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000090} xmlCatalogEntryType;
91
92typedef struct _xmlCatalogEntry xmlCatalogEntry;
93typedef xmlCatalogEntry *xmlCatalogEntryPtr;
94struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +000095 struct _xmlCatalogEntry *next;
96 struct _xmlCatalogEntry *parent;
97 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +000098 xmlCatalogEntryType type;
99 xmlChar *name;
100 xmlChar *value;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000101 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000102 int dealloc;
Daniel Veillarda7374592001-05-10 14:17:55 +0000103};
104
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000105static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000106static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +0000107static xmlHashTablePtr xmlDefaultCatalog;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000108static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard344cee72001-08-20 00:08:40 +0000109static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000110static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000111
Daniel Veillarda7374592001-05-10 14:17:55 +0000112
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000113/* Catalog stack */
Daniel Veillard81418e32001-05-22 15:08:55 +0000114static const char * catalTab[10]; /* stack of catals */
115static int catalNr = 0; /* Number of current catal streams */
116static int catalMax = 10; /* Max number of catal streams */
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000117
Daniel Veillard344cee72001-08-20 00:08:40 +0000118static int xmlDebugCatalogs = 0; /* used for debugging */
119
Daniel Veillarda7374592001-05-10 14:17:55 +0000120/************************************************************************
121 * *
122 * alloc or dealloc *
123 * *
124 ************************************************************************/
125
126static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000127xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000128 const xmlChar *value, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000129 xmlCatalogEntryPtr ret;
130
131 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
132 if (ret == NULL) {
133 xmlGenericError(xmlGenericErrorContext,
134 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
135 return(NULL);
136 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000137 ret->next = NULL;
138 ret->parent = NULL;
139 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000140 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000141 if (name != NULL)
142 ret->name = xmlStrdup(name);
143 else
144 ret->name = NULL;
145 if (value != NULL)
146 ret->value = xmlStrdup(value);
147 else
148 ret->value = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000149 ret->prefer = prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000150 ret->dealloc = 1;
Daniel Veillarda7374592001-05-10 14:17:55 +0000151 return(ret);
152}
153
154static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000155xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
156
157static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000158xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
159 if (ret == NULL)
160 return;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000161 if ((ret->children != NULL) && (ret->dealloc == 1))
Daniel Veillard344cee72001-08-20 00:08:40 +0000162 xmlFreeCatalogEntryList(ret->children);
Daniel Veillarda7374592001-05-10 14:17:55 +0000163 if (ret->name != NULL)
164 xmlFree(ret->name);
165 if (ret->value != NULL)
166 xmlFree(ret->value);
167 xmlFree(ret);
168}
169
Daniel Veillard344cee72001-08-20 00:08:40 +0000170static void
171xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
172 xmlCatalogEntryPtr next;
173
174 while (ret != NULL) {
175 next = ret->next;
176 xmlFreeCatalogEntry(ret);
177 ret = next;
178 }
179}
180
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000181/**
182 * xmlCatalogDumpEntry:
183 * @entry: the
184 * @out: the file.
185 *
186 * Free up all the memory associated with catalogs
187 */
188static void
189xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
190 if ((entry == NULL) || (out == NULL))
191 return;
192 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000193 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000194 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000195 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000196 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000197 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000198 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000199 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000200 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000201 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000202 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000203 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000204 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000205 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000206 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000207 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000208 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000209 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000210 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000211 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000212 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000213 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000214 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000215 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000216 fprintf(out, "SGMLDECL "); break;
217 default:
218 return;
219 }
220 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000221 case SGML_CATA_ENTITY:
222 case SGML_CATA_PENTITY:
223 case SGML_CATA_DOCTYPE:
224 case SGML_CATA_LINKTYPE:
225 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000226 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000227 case SGML_CATA_PUBLIC:
228 case SGML_CATA_SYSTEM:
229 case SGML_CATA_SGMLDECL:
230 case SGML_CATA_DOCUMENT:
231 case SGML_CATA_CATALOG:
232 case SGML_CATA_BASE:
233 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000234 fprintf(out, "\"%s\"", entry->name); break;
235 default:
236 break;
237 }
238 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000239 case SGML_CATA_ENTITY:
240 case SGML_CATA_PENTITY:
241 case SGML_CATA_DOCTYPE:
242 case SGML_CATA_LINKTYPE:
243 case SGML_CATA_NOTATION:
244 case SGML_CATA_PUBLIC:
245 case SGML_CATA_SYSTEM:
246 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000247 fprintf(out, " \"%s\"", entry->value); break;
248 default:
249 break;
250 }
251 fprintf(out, "\n");
252}
253
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000254/**
255 * xmlCatalogConvertEntry:
256 * @entry: the entry
257 * @res: pointer to te number converted
258 *
259 * Free up all the memory associated with catalogs
260 */
261static void
262xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, int *res) {
263 if ((entry == NULL) || (xmlDefaultXMLCatalogList == NULL))
264 return;
265 switch (entry->type) {
266 case SGML_CATA_ENTITY:
267 entry->type = XML_CATA_PUBLIC;
268 break;
269 case SGML_CATA_PENTITY:
270 entry->type = XML_CATA_PUBLIC;
271 break;
272 case SGML_CATA_DOCTYPE:
273 entry->type = XML_CATA_PUBLIC;
274 break;
275 case SGML_CATA_LINKTYPE:
276 entry->type = XML_CATA_PUBLIC;
277 break;
278 case SGML_CATA_NOTATION:
279 entry->type = XML_CATA_PUBLIC;
280 break;
281 case SGML_CATA_PUBLIC:
282 entry->type = XML_CATA_PUBLIC;
283 break;
284 case SGML_CATA_SYSTEM:
285 entry->type = XML_CATA_SYSTEM;
286 break;
287 case SGML_CATA_DELEGATE:
288 entry->type = XML_CATA_DELEGATE_PUBLIC;
289 break;
290 case SGML_CATA_CATALOG:
291 entry->type = XML_CATA_CATALOG;
292 break;
293 default:
294 xmlHashRemoveEntry(xmlDefaultCatalog, entry->name,
295 (xmlHashDeallocator) xmlFreeCatalogEntry);
296 return;
297 }
298 /*
299 * Conversion successful, remove from the SGML catalog
300 * and add it to the default XML one
301 */
302 xmlHashRemoveEntry(xmlDefaultCatalog, entry->name, NULL);
303 entry->parent = xmlDefaultXMLCatalogList;
304 entry->next = NULL;
305 if (xmlDefaultXMLCatalogList->children == NULL)
306 xmlDefaultXMLCatalogList->children = entry;
307 else {
308 xmlCatalogEntryPtr prev;
309
310 prev = xmlDefaultXMLCatalogList->children;
311 while (prev->next != NULL)
312 prev = prev->next;
313 prev->next = entry;
314 }
315 if (res != NULL)
316 (*res)++;
317}
318
Daniel Veillarda7374592001-05-10 14:17:55 +0000319/************************************************************************
320 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000321 * Helper function *
322 * *
323 ************************************************************************/
324
325/**
326 * xmlCatalogUnWrapURN:
327 * @urn: an "urn:publicid:" to unwrapp
328 *
329 * Expand the URN into the equivalent Public Identifier
330 *
331 * Returns the new identifier or NULL, the string must be deallocated
332 * by the caller.
333 */
334static xmlChar *
335xmlCatalogUnWrapURN(const xmlChar *urn) {
336 xmlChar result[2000];
337 unsigned int i = 0;
338
339 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
340 return(NULL);
341 urn += sizeof(XML_URN_PUBID) - 1;
342
343 while (*urn != 0) {
344 if (i > sizeof(result) - 3)
345 break;
346 if (*urn == '+') {
347 result[i++] = ' ';
348 urn++;
349 } else if (*urn == ':') {
350 result[i++] = '/';
351 result[i++] = '/';
352 urn++;
353 } else if (*urn == ';') {
354 result[i++] = ':';
355 result[i++] = ':';
356 urn++;
357 } else if (*urn == '%') {
358 if ((urn[1] == '2') && (urn[1] == 'B'))
359 result[i++] = '+';
360 else if ((urn[1] == '3') && (urn[1] == 'A'))
361 result[i++] = ':';
362 else if ((urn[1] == '2') && (urn[1] == 'F'))
363 result[i++] = '/';
364 else if ((urn[1] == '3') && (urn[1] == 'B'))
365 result[i++] = ';';
366 else if ((urn[1] == '2') && (urn[1] == '7'))
367 result[i++] = '\'';
368 else if ((urn[1] == '3') && (urn[1] == 'F'))
369 result[i++] = '?';
370 else if ((urn[1] == '2') && (urn[1] == '3'))
371 result[i++] = '#';
372 else if ((urn[1] == '2') && (urn[1] == '5'))
373 result[i++] = '%';
374 else {
375 result[i++] = *urn;
376 urn++;
377 continue;
378 }
379 urn += 3;
380 } else {
381 result[i++] = *urn;
382 urn++;
383 }
384 }
385 result[i] = 0;
386
387 return(xmlStrdup(result));
388}
389
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000390/**
391 * xmlParseCatalogFile:
392 * @filename: the filename
393 *
394 * parse an XML file and build a tree. It's like xmlParseFile()
395 * except it bypass all catalog lookups.
396 *
397 * Returns the resulting document tree or NULL in case of error
398 */
399
400xmlDocPtr
401xmlParseCatalogFile(const char *filename) {
402 xmlDocPtr ret;
403 xmlParserCtxtPtr ctxt;
404 char *directory = NULL;
405 xmlParserInputPtr inputStream;
406 xmlParserInputBufferPtr buf;
407
408 ctxt = xmlNewParserCtxt();
409 if (ctxt == NULL) {
410 if (xmlDefaultSAXHandler.error != NULL) {
411 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
412 }
413 return(NULL);
414 }
415
416 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
417 if (buf == NULL) {
418 xmlFreeParserCtxt(ctxt);
419 return(NULL);
420 }
421
422 inputStream = xmlNewInputStream(ctxt);
423 if (inputStream == NULL) {
424 xmlFreeParserCtxt(ctxt);
425 return(NULL);
426 }
427
428 inputStream->filename = xmlMemStrdup(filename);
429 inputStream->buf = buf;
430 inputStream->base = inputStream->buf->buffer->content;
431 inputStream->cur = inputStream->buf->buffer->content;
432 inputStream->end =
433 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
434
435 inputPush(ctxt, inputStream);
436 if ((ctxt->directory == NULL) && (directory == NULL))
437 directory = xmlParserGetDirectory(filename);
438 if ((ctxt->directory == NULL) && (directory != NULL))
439 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000440 ctxt->valid = 0;
441 ctxt->validate = 0;
442 ctxt->loadsubset = 0;
443 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000444
445 xmlParseDocument(ctxt);
446
447 if (ctxt->wellFormed)
448 ret = ctxt->myDoc;
449 else {
450 ret = NULL;
451 xmlFreeDoc(ctxt->myDoc);
452 ctxt->myDoc = NULL;
453 }
454 xmlFreeParserCtxt(ctxt);
455
456 return(ret);
457}
458
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000459/************************************************************************
460 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000461 * The XML Catalog parser *
462 * *
463 ************************************************************************/
464
465static xmlCatalogEntryPtr
466xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000467static xmlCatalogEntryPtr
468xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
469 const char *file);
470static void
471xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
472 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000473static xmlChar *
474xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
475 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000476static xmlChar *
477xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
478
Daniel Veillard344cee72001-08-20 00:08:40 +0000479
480static xmlCatalogEntryType
481xmlGetXMLCatalogEntryType(const xmlChar *name) {
482 xmlCatalogEntryType type = XML_CATA_NONE;
483 if (xmlStrEqual(name, (const xmlChar *) "system"))
484 type = XML_CATA_SYSTEM;
485 else if (xmlStrEqual(name, (const xmlChar *) "public"))
486 type = XML_CATA_PUBLIC;
487 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
488 type = XML_CATA_REWRITE_SYSTEM;
489 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
490 type = XML_CATA_DELEGATE_PUBLIC;
491 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
492 type = XML_CATA_DELEGATE_SYSTEM;
493 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
494 type = XML_CATA_URI;
495 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
496 type = XML_CATA_REWRITE_URI;
497 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
498 type = XML_CATA_DELEGATE_URI;
499 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
500 type = XML_CATA_NEXT_CATALOG;
501 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
502 type = XML_CATA_CATALOG;
503 return(type);
504}
505
506static xmlCatalogEntryPtr
507xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
508 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000509 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000510 int ok = 1;
511 xmlChar *uriValue;
512 xmlChar *nameValue = NULL;
513 xmlChar *base = NULL;
514 xmlChar *URL = NULL;
515 xmlCatalogEntryPtr ret = NULL;
516
517 if (attrName != NULL) {
518 nameValue = xmlGetProp(cur, attrName);
519 if (nameValue == NULL) {
520 xmlGenericError(xmlGenericErrorContext,
521 "%s entry lacks '%s'\n", name, attrName);
522 ok = 0;
523 }
524 }
525 uriValue = xmlGetProp(cur, uriAttrName);
526 if (uriValue == NULL) {
527 xmlGenericError(xmlGenericErrorContext,
528 "%s entry lacks '%s'\n", name, uriAttrName);
529 ok = 0;
530 }
531 if (!ok) {
532 if (nameValue != NULL)
533 xmlFree(nameValue);
534 if (uriValue != NULL)
535 xmlFree(uriValue);
536 return(NULL);
537 }
538
539 base = xmlNodeGetBase(cur->doc, cur);
540 URL = xmlBuildURI(uriValue, base);
541 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000542 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000543 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000544 xmlGenericError(xmlGenericErrorContext,
545 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000546 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000547 xmlGenericError(xmlGenericErrorContext,
548 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000549 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000550 ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000551 } else {
552 xmlGenericError(xmlGenericErrorContext,
553 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
554 }
555 if (nameValue != NULL)
556 xmlFree(nameValue);
557 if (uriValue != NULL)
558 xmlFree(uriValue);
559 if (base != NULL)
560 xmlFree(base);
561 if (URL != NULL)
562 xmlFree(URL);
563 return(ret);
564}
565
566static void
567xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
568 xmlCatalogEntryPtr parent)
569{
570 xmlChar *uri = NULL;
571 xmlChar *URL = NULL;
572 xmlChar *base = NULL;
573 xmlCatalogEntryPtr entry = NULL;
574
575 if (cur == NULL)
576 return;
577 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
578 xmlChar *prop;
579
580 prop = xmlGetProp(cur, BAD_CAST "prefer");
581 if (prop != NULL) {
582 if (xmlStrEqual(prop, BAD_CAST "system")) {
583 prefer = XML_CATA_PREFER_SYSTEM;
584 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
585 prefer = XML_CATA_PREFER_PUBLIC;
586 } else {
587 xmlGenericError(xmlGenericErrorContext,
588 "Invalid value for prefer: '%s'\n", prop);
589 }
590 xmlFree(prop);
591 }
592 /*
593 * Recurse to propagate prefer to the subtree
594 * (xml:base handling is automated)
595 */
596 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
597 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
598 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000599 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000600 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
601 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000602 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000603 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
604 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
605 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000606 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000607 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
608 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
609 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000610 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000611 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
612 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
613 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000614 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000615 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
616 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
617 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000618 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000619 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
620 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
621 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000622 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000623 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
624 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
625 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000626 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000627 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
628 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
629 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000630 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000631 }
632 if ((entry != NULL) && (parent != NULL)) {
633 entry->parent = parent;
634 if (parent->children == NULL)
635 parent->children = entry;
636 else {
637 xmlCatalogEntryPtr prev;
638
639 prev = parent->children;
640 while (prev->next != NULL)
641 prev = prev->next;
642 prev->next = entry;
643 }
644 }
645 if (base != NULL)
646 xmlFree(base);
647 if (uri != NULL)
648 xmlFree(uri);
649 if (URL != NULL)
650 xmlFree(URL);
651}
652
653static void
654xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
655 xmlCatalogEntryPtr parent) {
656 while (cur != NULL) {
657 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
658 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
659 xmlParseXMLCatalogNode(cur, prefer, parent);
660 }
661 cur = cur->next;
662 }
663 /* TODO: sort the list according to REWRITE lengths and prefer value */
664}
665
666static xmlCatalogEntryPtr
667xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
668 const char *file) {
669 xmlDocPtr doc;
670 xmlNodePtr cur;
671 xmlChar *prop;
672 xmlCatalogEntryPtr parent = NULL;
673
674 if ((value == NULL) || (file == NULL))
675 return(NULL);
676
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000677 if (xmlDebugCatalogs)
678 xmlGenericError(xmlGenericErrorContext,
679 "Parsing catalog %s's content\n", file);
680
Daniel Veillard344cee72001-08-20 00:08:40 +0000681 doc = xmlParseDoc((xmlChar *) value);
682 if (doc == NULL)
683 return(NULL);
684 doc->URL = xmlStrdup((const xmlChar *) file);
685
686 cur = xmlDocGetRootElement(doc);
687 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
688 (cur->ns != NULL) && (cur->ns->href != NULL) &&
689 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
690
Daniel Veillard344cee72001-08-20 00:08:40 +0000691 prop = xmlGetProp(cur, BAD_CAST "prefer");
692 if (prop != NULL) {
693 if (xmlStrEqual(prop, BAD_CAST "system")) {
694 prefer = XML_CATA_PREFER_SYSTEM;
695 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
696 prefer = XML_CATA_PREFER_PUBLIC;
697 } else {
698 xmlGenericError(xmlGenericErrorContext,
699 "Invalid value for prefer: '%s'\n",
700 prop);
701 }
702 xmlFree(prop);
703 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000704 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
705 (const xmlChar *)file, prefer);
706 if (parent == NULL) {
707 xmlFreeDoc(doc);
708 return(NULL);
709 }
710
Daniel Veillard344cee72001-08-20 00:08:40 +0000711 cur = cur->children;
712 xmlParseXMLCatalogNodeList(cur, prefer, parent);
713 } else {
714 xmlGenericError(xmlGenericErrorContext,
715 "File %s is not an XML Catalog\n", file);
716 xmlFreeDoc(doc);
717 return(NULL);
718 }
719 xmlFreeDoc(doc);
720 return(parent);
721}
722
723static xmlCatalogEntryPtr
724xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
725 xmlDocPtr doc;
726 xmlNodePtr cur;
727 xmlChar *prop;
728 xmlCatalogEntryPtr parent = NULL;
729
730 if (filename == NULL)
731 return(NULL);
732
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000733 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000734 if (doc == NULL) {
735 if (xmlDebugCatalogs)
736 xmlGenericError(xmlGenericErrorContext,
737 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000738 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000739 }
740
741 if (xmlDebugCatalogs)
742 xmlGenericError(xmlGenericErrorContext,
743 "Parsing catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000744
745 cur = xmlDocGetRootElement(doc);
746 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
747 (cur->ns != NULL) && (cur->ns->href != NULL) &&
748 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
749
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000750 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
751 (const xmlChar *)filename, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000752 if (parent == NULL) {
753 xmlFreeDoc(doc);
754 return(NULL);
755 }
756
757 prop = xmlGetProp(cur, BAD_CAST "prefer");
758 if (prop != NULL) {
759 if (xmlStrEqual(prop, BAD_CAST "system")) {
760 prefer = XML_CATA_PREFER_SYSTEM;
761 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
762 prefer = XML_CATA_PREFER_PUBLIC;
763 } else {
764 xmlGenericError(xmlGenericErrorContext,
765 "Invalid value for prefer: '%s'\n",
766 prop);
767 }
768 xmlFree(prop);
769 }
770 cur = cur->children;
771 xmlParseXMLCatalogNodeList(cur, prefer, parent);
772 } else {
773 xmlGenericError(xmlGenericErrorContext,
774 "File %s is not an XML Catalog\n", filename);
775 xmlFreeDoc(doc);
776 return(NULL);
777 }
778 xmlFreeDoc(doc);
779 return(parent);
780}
781
Daniel Veillardcda96922001-08-21 10:56:31 +0000782/**
783 * xmlFetchXMLCatalogFile:
784 * @catal: an existing but incomplete catalog entry
785 *
786 * Fetch and parse the subcatalog referenced by an entry
787 * It tries to be thread safe but by lack of an atomic test and
788 * set there is a risk of loosing memory.
789 *
790 * Returns 0 in case of success, -1 otherwise
791 */
792static int
793xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard6990bf32001-08-23 21:17:48 +0000794 xmlCatalogEntryPtr children = NULL, doc;
Daniel Veillardcda96922001-08-21 10:56:31 +0000795
796 if (catal == NULL)
797 return(-1);
798 if (catal->value == NULL)
799 return(-1);
800 if (catal->children != NULL)
801 return(-1);
802
Daniel Veillard6990bf32001-08-23 21:17:48 +0000803 if (xmlCatalogXMLFiles != NULL)
804 children = (xmlCatalogEntryPtr)
805 xmlHashLookup(xmlCatalogXMLFiles, catal->value);
806 if (children != NULL) {
807 catal->children = children;
808 catal->dealloc = 0;
809 return(0);
810 }
811
Daniel Veillardcda96922001-08-21 10:56:31 +0000812 /*
813 * Fetch and parse
814 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000815 doc = xmlParseXMLCatalogFile(catal->prefer, catal->value);
816 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000817 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillardcda96922001-08-21 10:56:31 +0000818 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000819 }
Daniel Veillard6990bf32001-08-23 21:17:48 +0000820 if ((catal->type == XML_CATA_CATALOG) &&
821 (doc->type == XML_CATA_CATALOG)) {
822 children = doc->children;
823 doc->children = NULL;
824 xmlFreeCatalogEntryList(doc);
825 } else {
826 children = doc;
827 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000828
829 /*
830 * Where a real test and set would be needed !
831 */
832 if (catal->children == NULL) {
833 catal->children = children;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000834 catal->dealloc = 1;
835 if (xmlCatalogXMLFiles == NULL)
836 xmlCatalogXMLFiles = xmlHashCreate(10);
837 if (xmlCatalogXMLFiles != NULL) {
838 if (children != NULL)
839 xmlHashAddEntry(xmlCatalogXMLFiles, catal->value, children);
840 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000841 } else {
842 /*
843 * Another thread filled it before us
844 */
845 xmlFreeCatalogEntryList(children);
846 }
847 return(0);
848}
849
Daniel Veillard344cee72001-08-20 00:08:40 +0000850static int
851xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
852 int ret;
853 xmlDocPtr doc;
854 xmlNsPtr ns;
855 xmlDtdPtr dtd;
856 xmlNodePtr node, catalog;
857 xmlOutputBufferPtr buf;
858 xmlCatalogEntryPtr cur;
859
860 /*
861 * Rebuild a catalog
862 */
863 doc = xmlNewDoc(NULL);
864 if (doc == NULL)
865 return(-1);
866 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
867 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
868BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
869
870 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
871
872 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
873 if (ns == NULL) {
874 xmlFreeDoc(doc);
875 return(-1);
876 }
877 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
878 if (catalog == NULL) {
879 xmlFreeNs(ns);
880 xmlFreeDoc(doc);
881 return(-1);
882 }
883 catalog->nsDef = ns;
884 xmlAddChild((xmlNodePtr) doc, catalog);
885
886 /*
887 * add all the catalog entries
888 */
889 cur = catal;
890 while (cur != NULL) {
891 switch (cur->type) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000892 case XML_CATA_BROKEN_CATALOG:
Daniel Veillard344cee72001-08-20 00:08:40 +0000893 case XML_CATA_CATALOG:
894 if (cur == catal) {
895 cur = cur->children;
896 continue;
897 }
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000898 break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000899 case XML_CATA_NEXT_CATALOG:
900 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
901 xmlSetProp(node, BAD_CAST "catalog", cur->value);
902 xmlAddChild(catalog, node);
903 break;
904 case XML_CATA_NONE:
905 break;
906 case XML_CATA_PUBLIC:
907 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
908 xmlSetProp(node, BAD_CAST "publicId", cur->name);
909 xmlSetProp(node, BAD_CAST "uri", cur->value);
910 xmlAddChild(catalog, node);
911 break;
912 case XML_CATA_SYSTEM:
913 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
914 xmlSetProp(node, BAD_CAST "systemId", cur->name);
915 xmlSetProp(node, BAD_CAST "uri", cur->value);
916 xmlAddChild(catalog, node);
917 break;
918 case XML_CATA_REWRITE_SYSTEM:
919 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
920 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
921 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
922 xmlAddChild(catalog, node);
923 break;
924 case XML_CATA_DELEGATE_PUBLIC:
925 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
926 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
927 xmlSetProp(node, BAD_CAST "catalog", cur->value);
928 xmlAddChild(catalog, node);
929 break;
930 case XML_CATA_DELEGATE_SYSTEM:
931 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
932 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
933 xmlSetProp(node, BAD_CAST "catalog", cur->value);
934 xmlAddChild(catalog, node);
935 break;
936 case XML_CATA_URI:
937 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
938 xmlSetProp(node, BAD_CAST "name", cur->name);
939 xmlSetProp(node, BAD_CAST "uri", cur->value);
940 xmlAddChild(catalog, node);
941 break;
942 case XML_CATA_REWRITE_URI:
943 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
944 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
945 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
946 xmlAddChild(catalog, node);
947 break;
948 case XML_CATA_DELEGATE_URI:
949 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
950 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
951 xmlSetProp(node, BAD_CAST "catalog", cur->value);
952 xmlAddChild(catalog, node);
953 break;
954 case SGML_CATA_SYSTEM:
955 case SGML_CATA_PUBLIC:
956 case SGML_CATA_ENTITY:
957 case SGML_CATA_PENTITY:
958 case SGML_CATA_DOCTYPE:
959 case SGML_CATA_LINKTYPE:
960 case SGML_CATA_NOTATION:
961 case SGML_CATA_DELEGATE:
962 case SGML_CATA_BASE:
963 case SGML_CATA_CATALOG:
964 case SGML_CATA_DOCUMENT:
965 case SGML_CATA_SGMLDECL:
966 break;
967 }
968 cur = cur->next;
969 }
970
971 /*
972 * reserialize it
973 */
974 buf = xmlOutputBufferCreateFile(out, NULL);
975 if (buf == NULL) {
976 xmlFreeDoc(doc);
977 return(-1);
978 }
979 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
980
981 /*
982 * Free it
983 */
984 xmlFreeDoc(doc);
985
986 return(ret);
987}
988
989/**
990 * xmlAddXMLCatalog:
991 * @catal: top of an XML catalog
992 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +0000993 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +0000994 * @replace: the replacement value for the match
995 *
996 * Add an entry in the XML catalog, it may overwrite existing but
997 * different entries.
998 *
999 * Returns 0 if successful, -1 otherwise
1000 */
1001static int
1002xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1003 const xmlChar *orig, const xmlChar *replace) {
1004 xmlCatalogEntryPtr cur;
1005 xmlCatalogEntryType typ;
1006
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001007 if ((catal == NULL) ||
1008 ((catal->type != XML_CATA_CATALOG) &&
1009 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001010 return(-1);
1011 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001012 if (typ == XML_CATA_NONE) {
1013 if (xmlDebugCatalogs)
1014 xmlGenericError(xmlGenericErrorContext,
1015 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001016 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001017 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001018
1019 cur = catal->children;
1020 /*
1021 * Might be a simple "update in place"
1022 */
1023 if (cur != NULL) {
1024 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001025 if ((orig != NULL) && (cur->type == typ) &&
1026 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001027 if (xmlDebugCatalogs)
1028 xmlGenericError(xmlGenericErrorContext,
1029 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001030 if (cur->value != NULL)
1031 xmlFree(cur->value);
1032 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001033 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001034 }
1035 if (cur->next == NULL)
1036 break;
1037 cur = cur->next;
1038 }
1039 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001040 if (xmlDebugCatalogs)
1041 xmlGenericError(xmlGenericErrorContext,
1042 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001043 if (cur == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001044 catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001045 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001046 cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillardcda96922001-08-21 10:56:31 +00001047 return(0);
1048}
1049
1050/**
1051 * xmlDelXMLCatalog:
1052 * @catal: top of an XML catalog
1053 * @value: the value to remove from teh catalog
1054 *
1055 * Remove entries in the XML catalog where the value or the URI
1056 * is equal to @value
1057 *
1058 * Returns the number of entries removed if successful, -1 otherwise
1059 */
1060static int
1061xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1062 xmlCatalogEntryPtr cur, prev, tmp;
1063 int ret = 0;
1064
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001065 if ((catal == NULL) ||
1066 ((catal->type != XML_CATA_CATALOG) &&
1067 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001068 return(-1);
1069 if (value == NULL)
1070 return(-1);
1071
1072 /*
1073 * Scan the children
1074 */
1075 cur = catal->children;
1076 prev = NULL;
1077 while (cur != NULL) {
1078 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1079 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001080 if (xmlDebugCatalogs) {
1081 if (cur->name != NULL)
1082 xmlGenericError(xmlGenericErrorContext,
1083 "Removing element %s from catalog\n", cur->name);
1084 else
1085 xmlGenericError(xmlGenericErrorContext,
1086 "Removing element %s from catalog\n", cur->value);
1087 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001088 ret++;
1089 tmp = cur;
1090 cur = tmp->next;
1091 if (prev == NULL) {
1092 catal->children = cur;
1093 } else {
1094 prev->next = cur;
1095 }
1096 xmlFreeCatalogEntry(tmp);
1097 continue;
1098 }
1099 prev = cur;
1100 cur = cur->next;
1101 }
1102 return(ret);
1103}
1104
1105/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001106 * xmlCatalogXMLResolve:
1107 * @catal: a catalog list
1108 * @pubId: the public ID string
1109 * @sysId: the system ID string
1110 *
1111 * Do a complete resolution lookup of an External Identifier for a
1112 * list of catalog entries.
1113 *
1114 * Implements (or tries to) 7.1. External Identifier Resolution
1115 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1116 *
1117 * Returns the URI of the resource or NULL if not found
1118 */
1119static xmlChar *
1120xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1121 const xmlChar *sysID) {
1122 xmlChar *ret = NULL;
1123 xmlCatalogEntryPtr cur;
1124 int haveDelegate = 0;
1125 int haveNext = 0;
1126
1127 /*
1128 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1129 */
1130 if (sysID != NULL) {
1131 xmlCatalogEntryPtr rewrite = NULL;
1132 int lenrewrite = 0, len;
1133 cur = catal;
1134 haveDelegate = 0;
1135 while (cur != NULL) {
1136 switch (cur->type) {
1137 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001138 if (xmlStrEqual(sysID, cur->name)) {
1139 if (xmlDebugCatalogs)
1140 xmlGenericError(xmlGenericErrorContext,
1141 "Found system match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001142 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001143 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001144 break;
1145 case XML_CATA_REWRITE_SYSTEM:
1146 len = xmlStrlen(cur->name);
1147 if ((len > lenrewrite) &&
1148 (!xmlStrncmp(sysID, cur->name, len))) {
1149 lenrewrite = len;
1150 rewrite = cur;
1151 }
1152 break;
1153 case XML_CATA_DELEGATE_SYSTEM:
1154 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1155 haveDelegate++;
1156 break;
1157 case XML_CATA_NEXT_CATALOG:
1158 haveNext++;
1159 break;
1160 default:
1161 break;
1162 }
1163 cur = cur->next;
1164 }
1165 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001166 if (xmlDebugCatalogs)
1167 xmlGenericError(xmlGenericErrorContext,
1168 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001169 ret = xmlStrdup(rewrite->value);
1170 if (ret != NULL)
1171 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1172 return(ret);
1173 }
1174 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001175 const xmlChar *delegates[MAX_DELEGATE];
1176 int nbList = 0, i;
1177
Daniel Veillardcda96922001-08-21 10:56:31 +00001178 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001179 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001180 * matches when the list was produced.
1181 */
1182 cur = catal;
1183 while (cur != NULL) {
1184 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1185 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001186 for (i = 0;i < nbList;i++)
1187 if (xmlStrEqual(cur->value, delegates[i]))
1188 break;
1189 if (i < nbList) {
1190 cur = cur->next;
1191 continue;
1192 }
1193 if (nbList < MAX_DELEGATE)
1194 delegates[nbList++] = cur->value;
1195
Daniel Veillardcda96922001-08-21 10:56:31 +00001196 if (cur->children == NULL) {
1197 xmlFetchXMLCatalogFile(cur);
1198 }
1199 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001200 if (xmlDebugCatalogs)
1201 xmlGenericError(xmlGenericErrorContext,
1202 "Trying system delegate %s\n", cur->value);
1203 ret = xmlCatalogListXMLResolve(cur->children, NULL,
1204 sysID);
1205 if (ret != NULL)
1206 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001207 }
1208 }
1209 cur = cur->next;
1210 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001211 /*
1212 * Apply the cut algorithm explained in 4/
1213 */
1214 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001215 }
1216 }
1217 /*
1218 * Then tries 5/ 6/ if a public ID is provided
1219 */
1220 if (pubID != NULL) {
1221 cur = catal;
1222 haveDelegate = 0;
1223 while (cur != NULL) {
1224 switch (cur->type) {
1225 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001226 if (xmlStrEqual(pubID, cur->name)) {
1227 if (xmlDebugCatalogs)
1228 xmlGenericError(xmlGenericErrorContext,
1229 "Found public match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001230 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001231 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001232 break;
1233 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001234 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1235 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001236 haveDelegate++;
1237 break;
1238 case XML_CATA_NEXT_CATALOG:
1239 if (sysID == NULL)
1240 haveNext++;
1241 break;
1242 default:
1243 break;
1244 }
1245 cur = cur->next;
1246 }
1247 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001248 const xmlChar *delegates[MAX_DELEGATE];
1249 int nbList = 0, i;
1250
Daniel Veillardcda96922001-08-21 10:56:31 +00001251 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001252 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001253 * matches when the list was produced.
1254 */
1255 cur = catal;
1256 while (cur != NULL) {
1257 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001258 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1259 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001260
1261 for (i = 0;i < nbList;i++)
1262 if (xmlStrEqual(cur->value, delegates[i]))
1263 break;
1264 if (i < nbList) {
1265 cur = cur->next;
1266 continue;
1267 }
1268 if (nbList < MAX_DELEGATE)
1269 delegates[nbList++] = cur->value;
1270
Daniel Veillardcda96922001-08-21 10:56:31 +00001271 if (cur->children == NULL) {
1272 xmlFetchXMLCatalogFile(cur);
1273 }
1274 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001275 if (xmlDebugCatalogs)
1276 xmlGenericError(xmlGenericErrorContext,
1277 "Trying public delegate %s\n", cur->value);
1278 ret = xmlCatalogListXMLResolve(cur->children, pubID,
1279 NULL);
1280 if (ret != NULL)
1281 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001282 }
1283 }
1284 cur = cur->next;
1285 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001286 /*
1287 * Apply the cut algorithm explained in 4/
1288 */
1289 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001290 }
1291 }
1292 if (haveNext) {
1293 cur = catal;
1294 while (cur != NULL) {
1295 if (cur->type == XML_CATA_NEXT_CATALOG) {
1296 if (cur->children == NULL) {
1297 xmlFetchXMLCatalogFile(cur);
1298 }
1299 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001300 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1301 if (ret != NULL)
1302 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001303 }
1304 }
1305 cur = cur->next;
1306 }
1307 }
1308
1309 return(NULL);
1310}
1311
1312/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001313 * xmlCatalogXMLResolveURI:
1314 * @catal: a catalog list
1315 * @URI: the URI
1316 * @sysId: the system ID string
1317 *
1318 * Do a complete resolution lookup of an External Identifier for a
1319 * list of catalog entries.
1320 *
1321 * Implements (or tries to) 7.2.2. URI Resolution
1322 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1323 *
1324 * Returns the URI of the resource or NULL if not found
1325 */
1326static xmlChar *
1327xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1328 xmlChar *ret = NULL;
1329 xmlCatalogEntryPtr cur;
1330 int haveDelegate = 0;
1331 int haveNext = 0;
1332 xmlCatalogEntryPtr rewrite = NULL;
1333 int lenrewrite = 0, len;
1334
1335 if (catal == NULL)
1336 return(NULL);
1337
1338 if (URI == NULL)
1339 return(NULL);
1340
1341 /*
1342 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1343 */
1344 cur = catal;
1345 haveDelegate = 0;
1346 while (cur != NULL) {
1347 switch (cur->type) {
1348 case XML_CATA_URI:
1349 if (xmlStrEqual(URI, cur->name)) {
1350 if (xmlDebugCatalogs)
1351 xmlGenericError(xmlGenericErrorContext,
1352 "Found URI match %s\n", cur->name);
1353 return(xmlStrdup(cur->value));
1354 }
1355 break;
1356 case XML_CATA_REWRITE_URI:
1357 len = xmlStrlen(cur->name);
1358 if ((len > lenrewrite) &&
1359 (!xmlStrncmp(URI, cur->name, len))) {
1360 lenrewrite = len;
1361 rewrite = cur;
1362 }
1363 break;
1364 case XML_CATA_DELEGATE_URI:
1365 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1366 haveDelegate++;
1367 break;
1368 case XML_CATA_NEXT_CATALOG:
1369 haveNext++;
1370 break;
1371 default:
1372 break;
1373 }
1374 cur = cur->next;
1375 }
1376 if (rewrite != NULL) {
1377 if (xmlDebugCatalogs)
1378 xmlGenericError(xmlGenericErrorContext,
1379 "Using rewriting rule %s\n", rewrite->name);
1380 ret = xmlStrdup(rewrite->value);
1381 if (ret != NULL)
1382 ret = xmlStrcat(ret, &URI[lenrewrite]);
1383 return(ret);
1384 }
1385 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001386 const xmlChar *delegates[MAX_DELEGATE];
1387 int nbList = 0, i;
1388
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001389 /*
1390 * Assume the entries have been sorted by decreasing substring
1391 * matches when the list was produced.
1392 */
1393 cur = catal;
1394 while (cur != NULL) {
1395 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1396 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001397 for (i = 0;i < nbList;i++)
1398 if (xmlStrEqual(cur->value, delegates[i]))
1399 break;
1400 if (i < nbList) {
1401 cur = cur->next;
1402 continue;
1403 }
1404 if (nbList < MAX_DELEGATE)
1405 delegates[nbList++] = cur->value;
1406
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001407 if (cur->children == NULL) {
1408 xmlFetchXMLCatalogFile(cur);
1409 }
1410 if (cur->children != NULL) {
1411 if (xmlDebugCatalogs)
1412 xmlGenericError(xmlGenericErrorContext,
1413 "Trying URI delegate %s\n", cur->value);
1414 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1415 if (ret != NULL)
1416 return(ret);
1417 }
1418 }
1419 cur = cur->next;
1420 }
1421 /*
1422 * Apply the cut algorithm explained in 4/
1423 */
1424 return(XML_CATAL_BREAK);
1425 }
1426 if (haveNext) {
1427 cur = catal;
1428 while (cur != NULL) {
1429 if (cur->type == XML_CATA_NEXT_CATALOG) {
1430 if (cur->children == NULL) {
1431 xmlFetchXMLCatalogFile(cur);
1432 }
1433 if (cur->children != NULL) {
1434 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1435 if (ret != NULL)
1436 return(ret);
1437 }
1438 }
1439 cur = cur->next;
1440 }
1441 }
1442
1443 return(NULL);
1444}
1445
1446/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001447 * xmlCatalogListXMLResolve:
1448 * @catal: a catalog list
1449 * @pubId: the public ID string
1450 * @sysId: the system ID string
1451 *
1452 * Do a complete resolution lookup of an External Identifier for a
1453 * list of catalogs
1454 *
1455 * Implements (or tries to) 7.1. External Identifier Resolution
1456 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1457 *
1458 * Returns the URI of the resource or NULL if not found
1459 */
1460static xmlChar *
1461xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1462 const xmlChar *sysID) {
1463 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001464 xmlChar *urnID = NULL;
1465
1466 if (catal == NULL)
1467 return(NULL);
1468 if ((pubID == NULL) && (sysID == NULL))
1469 return(NULL);
1470
1471 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1472 urnID = xmlCatalogUnWrapURN(pubID);
1473 if (xmlDebugCatalogs) {
1474 if (urnID == NULL)
1475 xmlGenericError(xmlGenericErrorContext,
1476 "Public URN ID %s expanded to NULL\n", pubID);
1477 else
1478 xmlGenericError(xmlGenericErrorContext,
1479 "Public URN ID expanded to %s\n", urnID);
1480 }
1481 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1482 if (urnID != NULL)
1483 xmlFree(urnID);
1484 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001485 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001486 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1487 urnID = xmlCatalogUnWrapURN(sysID);
1488 if (xmlDebugCatalogs) {
1489 if (urnID == NULL)
1490 xmlGenericError(xmlGenericErrorContext,
1491 "System URN ID %s expanded to NULL\n", sysID);
1492 else
1493 xmlGenericError(xmlGenericErrorContext,
1494 "System URN ID expanded to %s\n", urnID);
1495 }
1496 if (pubID == NULL)
1497 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1498 else if (xmlStrEqual(pubID, urnID))
1499 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1500 else {
1501 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1502 }
1503 if (urnID != NULL)
1504 xmlFree(urnID);
1505 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001506 }
1507 while (catal != NULL) {
1508 if (catal->type == XML_CATA_CATALOG) {
1509 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001510 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001511 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001512 if (catal->children != NULL) {
1513 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1514 if (ret != NULL)
1515 return(ret);
1516 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001517 }
1518 catal = catal->next;
1519 }
1520 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001521}
1522
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001523/**
1524 * xmlCatalogListXMLResolveURI:
1525 * @catal: a catalog list
1526 * @URI: the URI
1527 *
1528 * Do a complete resolution lookup of an URI for a list of catalogs
1529 *
1530 * Implements (or tries to) 7.2. URI Resolution
1531 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1532 *
1533 * Returns the URI of the resource or NULL if not found
1534 */
1535static xmlChar *
1536xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1537 xmlChar *ret = NULL;
1538 xmlChar *urnID = NULL;
1539
1540 if (catal == NULL)
1541 return(NULL);
1542 if (URI == NULL)
1543 return(NULL);
1544
1545 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1546 urnID = xmlCatalogUnWrapURN(URI);
1547 if (xmlDebugCatalogs) {
1548 if (urnID == NULL)
1549 xmlGenericError(xmlGenericErrorContext,
1550 "URN ID %s expanded to NULL\n", URI);
1551 else
1552 xmlGenericError(xmlGenericErrorContext,
1553 "URN ID expanded to %s\n", urnID);
1554 }
1555 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1556 if (urnID != NULL)
1557 xmlFree(urnID);
1558 return(ret);
1559 }
1560 while (catal != NULL) {
1561 if (catal->type == XML_CATA_CATALOG) {
1562 if (catal->children == NULL) {
1563 xmlFetchXMLCatalogFile(catal);
1564 }
1565 if (catal->children != NULL) {
1566 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1567 if (ret != NULL)
1568 return(ret);
1569 }
1570 }
1571 catal = catal->next;
1572 }
1573 return(ret);
1574}
1575
Daniel Veillard344cee72001-08-20 00:08:40 +00001576/************************************************************************
1577 * *
1578 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001579 * *
1580 ************************************************************************/
1581
1582
1583#define RAW *cur
1584#define NEXT cur++;
1585#define SKIP(x) cur += x;
1586
1587#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1588
1589static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001590xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001591 if ((cur[0] != '-') || (cur[1] != '-'))
1592 return(cur);
1593 SKIP(2);
1594 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1595 NEXT;
1596 if (cur[0] == 0) {
1597 return(NULL);
1598 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001599 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001600}
1601
1602static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001603xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001604 xmlChar *buf = NULL;
1605 int len = 0;
1606 int size = 50;
1607 xmlChar stop;
1608 int count = 0;
1609
1610 *id = NULL;
1611
1612 if (RAW == '"') {
1613 NEXT;
1614 stop = '"';
1615 } else if (RAW == '\'') {
1616 NEXT;
1617 stop = '\'';
1618 } else {
1619 stop = ' ';
1620 }
1621 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1622 if (buf == NULL) {
1623 xmlGenericError(xmlGenericErrorContext,
1624 "malloc of %d byte failed\n", size);
1625 return(NULL);
1626 }
1627 while (xmlIsPubidChar(*cur)) {
1628 if ((*cur == stop) && (stop != ' '))
1629 break;
1630 if ((stop == ' ') && (IS_BLANK(*cur)))
1631 break;
1632 if (len + 1 >= size) {
1633 size *= 2;
1634 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1635 if (buf == NULL) {
1636 xmlGenericError(xmlGenericErrorContext,
1637 "realloc of %d byte failed\n", size);
1638 return(NULL);
1639 }
1640 }
1641 buf[len++] = *cur;
1642 count++;
1643 NEXT;
1644 }
1645 buf[len] = 0;
1646 if (stop == ' ') {
1647 if (!IS_BLANK(*cur)) {
1648 xmlFree(buf);
1649 return(NULL);
1650 }
1651 } else {
1652 if (*cur != stop) {
1653 xmlFree(buf);
1654 return(NULL);
1655 }
1656 NEXT;
1657 }
1658 *id = buf;
1659 return(cur);
1660}
1661
1662static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001663xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001664 xmlChar buf[XML_MAX_NAMELEN + 5];
1665 int len = 0;
1666 int c;
1667
1668 *name = NULL;
1669
1670 /*
1671 * Handler for more complex cases
1672 */
1673 c = *cur;
1674 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
1675 return(NULL);
1676 }
1677
1678 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
1679 (c == '.') || (c == '-') ||
1680 (c == '_') || (c == ':'))) {
1681 buf[len++] = c;
1682 cur++;
1683 c = *cur;
1684 if (len >= XML_MAX_NAMELEN)
1685 return(NULL);
1686 }
1687 *name = xmlStrndup(buf, len);
1688 return(cur);
1689}
1690
Daniel Veillard344cee72001-08-20 00:08:40 +00001691static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00001692xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001693 xmlCatalogEntryType type = XML_CATA_NONE;
1694 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
1695 type = SGML_CATA_SYSTEM;
1696 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
1697 type = SGML_CATA_PUBLIC;
1698 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1699 type = SGML_CATA_DELEGATE;
1700 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
1701 type = SGML_CATA_ENTITY;
1702 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
1703 type = SGML_CATA_DOCTYPE;
1704 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
1705 type = SGML_CATA_LINKTYPE;
1706 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
1707 type = SGML_CATA_NOTATION;
1708 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
1709 type = SGML_CATA_SGMLDECL;
1710 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
1711 type = SGML_CATA_DOCUMENT;
1712 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
1713 type = SGML_CATA_CATALOG;
1714 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
1715 type = SGML_CATA_BASE;
1716 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1717 type = SGML_CATA_DELEGATE;
1718 return(type);
1719}
1720
Daniel Veillarda7374592001-05-10 14:17:55 +00001721static int
Daniel Veillard82d75332001-10-08 15:01:59 +00001722xmlParseSGMLCatalog(const xmlChar *value, const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001723 const xmlChar *cur = value;
1724 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001725 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00001726
1727 if ((cur == NULL) || (file == NULL))
1728 return(-1);
1729 base = xmlStrdup((const xmlChar *) file);
1730
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00001731 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001732 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00001733 if (cur[0] == 0)
1734 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00001735 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001736 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00001737 if (cur == NULL) {
1738 /* error */
1739 break;
1740 }
1741 } else {
1742 xmlChar *sysid = NULL;
1743 xmlChar *name = NULL;
1744 xmlCatalogEntryType type = XML_CATA_NONE;
1745
Daniel Veillardcda96922001-08-21 10:56:31 +00001746 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001747 if (name == NULL) {
1748 /* error */
1749 break;
1750 }
1751 if (!IS_BLANK(*cur)) {
1752 /* error */
1753 break;
1754 }
1755 SKIP_BLANKS;
1756 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001757 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00001758 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001759 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00001760 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001761 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001762 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001763 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00001764 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001765 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001766 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001767 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001768 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001769 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00001770 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001771 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001772 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001773 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00001774 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001775 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00001776 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001777 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001778 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001779 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001780 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
1781 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001782 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001783 if (name == NULL) {
1784 /* error */
1785 break;
1786 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001787 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001788 continue;
1789 }
1790 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001791 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001792
1793 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001794 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00001795 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00001796 type = SGML_CATA_PENTITY;
1797 case SGML_CATA_PENTITY:
1798 case SGML_CATA_DOCTYPE:
1799 case SGML_CATA_LINKTYPE:
1800 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00001801 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001802 if (cur == NULL) {
1803 /* error */
1804 break;
1805 }
1806 if (!IS_BLANK(*cur)) {
1807 /* error */
1808 break;
1809 }
1810 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001811 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001812 if (cur == NULL) {
1813 /* error */
1814 break;
1815 }
1816 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001817 case SGML_CATA_PUBLIC:
1818 case SGML_CATA_SYSTEM:
1819 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00001820 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001821 if (cur == NULL) {
1822 /* error */
1823 break;
1824 }
1825 if (!IS_BLANK(*cur)) {
1826 /* error */
1827 break;
1828 }
1829 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001830 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001831 if (cur == NULL) {
1832 /* error */
1833 break;
1834 }
1835 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001836 case SGML_CATA_BASE:
1837 case SGML_CATA_CATALOG:
1838 case SGML_CATA_DOCUMENT:
1839 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00001840 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001841 if (cur == NULL) {
1842 /* error */
1843 break;
1844 }
1845 break;
1846 default:
1847 break;
1848 }
1849 if (cur == NULL) {
1850 if (name != NULL)
1851 xmlFree(name);
1852 if (sysid != NULL)
1853 xmlFree(sysid);
1854 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001855 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001856 if (base != NULL)
1857 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001858 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00001859 } else if ((type == SGML_CATA_PUBLIC) ||
1860 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001861 xmlChar *filename;
1862
1863 filename = xmlBuildURI(sysid, base);
1864 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001865 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00001866
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001867 entry = xmlNewCatalogEntry(type, name, filename,
1868 XML_CATA_PREFER_NONE);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001869 res = xmlHashAddEntry(xmlDefaultCatalog, name, entry);
1870 if (res < 0) {
1871 xmlFreeCatalogEntry(entry);
1872 }
1873 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00001874 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001875
Daniel Veillard344cee72001-08-20 00:08:40 +00001876 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00001877 if (super) {
1878 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001879
Daniel Veillard82d75332001-10-08 15:01:59 +00001880 entry = xmlNewCatalogEntry(type, sysid, NULL,
1881 XML_CATA_PREFER_NONE);
1882 res = xmlHashAddEntry(xmlDefaultCatalog, sysid, entry);
1883 if (res < 0) {
1884 xmlFreeCatalogEntry(entry);
1885 }
1886 } else {
1887 xmlChar *filename;
1888
1889 filename = xmlBuildURI(sysid, base);
1890 if (filename != NULL) {
1891 xmlLoadCatalog((const char *)filename);
1892 xmlFree(filename);
1893 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001894 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001895 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001896 /*
1897 * drop anything else we won't handle it
1898 */
1899 if (name != NULL)
1900 xmlFree(name);
1901 if (sysid != NULL)
1902 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001903 }
1904 }
1905 if (base != NULL)
1906 xmlFree(base);
1907 if (cur == NULL)
1908 return(-1);
1909 return(0);
1910}
1911
Daniel Veillardcda96922001-08-21 10:56:31 +00001912/**
1913 * xmlCatalogGetSGMLPublic:
1914 * @catal: an SGML catalog hash
1915 * @pubId: the public ID string
1916 *
1917 * Try to lookup the system ID associated to a public ID
1918 *
1919 * Returns the system ID if found or NULL otherwise.
1920 */
1921static const xmlChar *
1922xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
1923 xmlCatalogEntryPtr entry;
1924
1925 if (catal == NULL)
1926 return(NULL);
1927
1928 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
1929 if (entry == NULL)
1930 return(NULL);
1931 if (entry->type == SGML_CATA_PUBLIC)
1932 return(entry->value);
1933 return(NULL);
1934}
1935
1936/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001937 * xmlCatalogGetSGMLSystem:
1938 * @catal: an SGML catalog hash
1939 * @sysId: the public ID string
1940 *
1941 * Try to lookup the catalog local reference for a system ID
1942 *
1943 * Returns the system ID if found or NULL otherwise.
1944 */
1945static const xmlChar *
1946xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
1947 xmlCatalogEntryPtr entry;
1948
1949 if (catal == NULL)
1950 return(NULL);
1951
1952 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
1953 if (entry == NULL)
1954 return(NULL);
1955 if (entry->type == SGML_CATA_SYSTEM)
1956 return(entry->value);
1957 return(NULL);
1958}
1959
1960/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001961 * xmlCatalogSGMLResolve:
1962 * @pubId: the public ID string
1963 * @sysId: the system ID string
1964 *
1965 * Do a complete resolution lookup of an External Identifier
1966 *
1967 * Returns the URI of the resource or NULL if not found
1968 */
1969static const xmlChar *
1970xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00001971 const xmlChar *ret = NULL;
1972
1973 if (xmlDefaultCatalog == NULL)
1974 return(NULL);
1975
1976 if (pubID != NULL)
1977 ret = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
1978 if (ret != NULL)
1979 return(ret);
1980 if (sysID != NULL)
1981 ret = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00001982 return(NULL);
1983}
1984
Daniel Veillarda7374592001-05-10 14:17:55 +00001985/************************************************************************
1986 * *
1987 * Public interfaces *
1988 * *
1989 ************************************************************************/
1990
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001991/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001992 * xmlInitializeCatalog:
1993 *
1994 * Do the catalog initialization.
1995 * TODO: this function is not thread safe, catalog initialization should
1996 * preferably be done once at startup
1997 */
1998void
1999xmlInitializeCatalog(void) {
2000 const char *catalogs;
2001
2002 if (xmlCatalogInitialized != 0)
2003 return;
2004
2005 if (getenv("XML_DEBUG_CATALOG"))
2006 xmlDebugCatalogs = 1;
2007 if ((xmlDefaultXMLCatalogList == NULL) && (xmlDefaultCatalog == NULL)) {
2008 catalogs = getenv("XML_CATALOG_FILES");
2009 if (catalogs == NULL)
2010 catalogs = XML_DEFAULT_CATALOG;
2011 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
2012 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
2013 }
2014
2015 xmlCatalogInitialized = 1;
2016}
2017
2018/**
Daniel Veillard82d75332001-10-08 15:01:59 +00002019 * xmlLoadSGMLSuperCatalog:
2020 * @filename: a file path
2021 *
2022 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2023 * references. This is only needed for manipulating SGML Super Catalogs
2024 * like adding and removing CATALOG or DELEGATE entries.
2025 *
2026 * Returns 0 in case of success -1 in case of error
2027 */
2028int
2029xmlLoadSGMLSuperCatalog(const char *filename)
2030{
2031#ifdef HAVE_STAT
2032 int fd;
2033#else
2034 FILE *fd;
2035#endif
2036 int len, ret;
2037 long size;
2038
2039#ifdef HAVE_STAT
2040 struct stat info;
2041#endif
2042 xmlChar *content;
2043
2044 if (filename == NULL)
2045 return (-1);
2046
2047 if (xmlDefaultCatalog == NULL)
2048 xmlDefaultCatalog = xmlHashCreate(20);
2049 if (xmlDefaultCatalog == NULL)
2050 return (-1);
2051
2052#ifdef HAVE_STAT
2053 if (stat(filename, &info) < 0)
2054 return (-1);
2055#endif
2056
2057#ifdef HAVE_STAT
2058 if ((fd = open(filename, O_RDONLY)) < 0) {
2059#else
2060 if ((fd = fopen(filename, "rb")) == NULL) {
2061#endif
2062 catalNr--;
2063 return (-1);
2064 }
2065#ifdef HAVE_STAT
2066 size = info.st_size;
2067#else
2068 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
2069 fclose(fd);
2070 return (-1);
2071 }
2072#endif
2073 content = xmlMalloc(size + 10);
2074 if (content == NULL) {
2075 xmlGenericError(xmlGenericErrorContext,
2076 "realloc of %d byte failed\n", size + 10);
2077 catalNr--;
2078 return (-1);
2079 }
2080#ifdef HAVE_STAT
2081 len = read(fd, content, size);
2082#else
2083 len = fread(content, 1, size, fd);
2084#endif
2085 if (len < 0) {
2086 xmlFree(content);
2087 catalNr--;
2088 return (-1);
2089 }
2090 content[len] = 0;
2091#ifdef HAVE_STAT
2092 close(fd);
2093#else
2094 fclose(fd);
2095#endif
2096
2097 ret = xmlParseSGMLCatalog(content, filename, 1);
2098
2099 xmlFree(content);
2100 return (ret);
2101}
2102
2103/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002104 * xmlLoadCatalog:
2105 * @filename: a file path
2106 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002107 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002108 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002109 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002110 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002111 *
2112 * Returns 0 in case of success -1 in case of error
2113 */
2114int
Daniel Veillard16756b62001-10-01 07:36:25 +00002115xmlLoadCatalog(const char *filename)
2116{
2117#ifdef HAVE_STAT
2118 int fd;
2119#else
2120 FILE *fd;
2121#endif
2122 int len, ret, i;
2123 long size;
2124
2125#ifdef HAVE_STAT
Daniel Veillarda7374592001-05-10 14:17:55 +00002126 struct stat info;
Daniel Veillard16756b62001-10-01 07:36:25 +00002127#endif
Daniel Veillarda7374592001-05-10 14:17:55 +00002128 xmlChar *content;
2129
2130 if (filename == NULL)
Daniel Veillard16756b62001-10-01 07:36:25 +00002131 return (-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002132
Daniel Veillarda7374592001-05-10 14:17:55 +00002133 if (xmlDefaultCatalog == NULL)
Daniel Veillard16756b62001-10-01 07:36:25 +00002134 xmlDefaultCatalog = xmlHashCreate(20);
Daniel Veillarda7374592001-05-10 14:17:55 +00002135 if (xmlDefaultCatalog == NULL)
Daniel Veillard16756b62001-10-01 07:36:25 +00002136 return (-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002137
2138 /*
2139 * Need to be done after ...
2140 */
2141 if (!xmlCatalogInitialized)
Daniel Veillard16756b62001-10-01 07:36:25 +00002142 xmlInitializeCatalog();
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002143
2144#ifdef HAVE_STAT
Daniel Veillard16756b62001-10-01 07:36:25 +00002145 if (stat(filename, &info) < 0)
2146 return (-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002147#endif
Daniel Veillarda7374592001-05-10 14:17:55 +00002148
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002149 /*
2150 * Prevent loops
2151 */
Daniel Veillard16756b62001-10-01 07:36:25 +00002152 for (i = 0; i < catalNr; i++) {
2153 if (xmlStrEqual((const xmlChar *) catalTab[i],
2154 (const xmlChar *) filename)) {
2155 xmlGenericError(xmlGenericErrorContext,
2156 "xmlLoadCatalog: %s seems to induce a loop\n",
2157 filename);
2158 return (-1);
2159 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002160 }
2161 if (catalNr >= catalMax) {
Daniel Veillard16756b62001-10-01 07:36:25 +00002162 xmlGenericError(xmlGenericErrorContext,
2163 "xmlLoadCatalog: %s catalog list too deep\n",
2164 filename);
2165 return (-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002166 }
2167 catalTab[catalNr++] = filename;
2168
Daniel Veillard16756b62001-10-01 07:36:25 +00002169#ifdef HAVE_STAT
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002170 if ((fd = open(filename, O_RDONLY)) < 0) {
Daniel Veillard16756b62001-10-01 07:36:25 +00002171#else
2172 if ((fd = fopen(filename, "rb")) == NULL) {
2173#endif
2174 catalNr--;
2175 return (-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002176 }
Daniel Veillard16756b62001-10-01 07:36:25 +00002177#ifdef HAVE_STAT
2178 size = info.st_size;
2179#else
2180 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
2181 fclose(fd);
2182 return (-1);
2183 }
2184#endif
2185 content = xmlMalloc(size + 10);
Daniel Veillarda7374592001-05-10 14:17:55 +00002186 if (content == NULL) {
Daniel Veillard16756b62001-10-01 07:36:25 +00002187 xmlGenericError(xmlGenericErrorContext,
2188 "realloc of %d byte failed\n", size + 10);
2189 catalNr--;
2190 return (-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002191 }
Daniel Veillard16756b62001-10-01 07:36:25 +00002192#ifdef HAVE_STAT
2193 len = read(fd, content, size);
2194#else
2195 len = fread(content, 1, size, fd);
2196#endif
Daniel Veillarda7374592001-05-10 14:17:55 +00002197 if (len < 0) {
Daniel Veillard16756b62001-10-01 07:36:25 +00002198 xmlFree(content);
2199 catalNr--;
2200 return (-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002201 }
2202 content[len] = 0;
Daniel Veillard16756b62001-10-01 07:36:25 +00002203#ifdef HAVE_STAT
Daniel Veillarda7374592001-05-10 14:17:55 +00002204 close(fd);
Daniel Veillard16756b62001-10-01 07:36:25 +00002205#else
2206 fclose(fd);
2207#endif
Daniel Veillarda7374592001-05-10 14:17:55 +00002208
Daniel Veillard344cee72001-08-20 00:08:40 +00002209 if ((content[0] == ' ') || (content[0] == '-') ||
Daniel Veillard16756b62001-10-01 07:36:25 +00002210 ((content[0] >= 'A') && (content[0] <= 'Z')) ||
2211 ((content[0] >= 'a') && (content[0] <= 'z')))
Daniel Veillard82d75332001-10-08 15:01:59 +00002212 ret = xmlParseSGMLCatalog(content, filename, 0);
Daniel Veillard344cee72001-08-20 00:08:40 +00002213 else {
Daniel Veillard16756b62001-10-01 07:36:25 +00002214 xmlCatalogEntryPtr catal, tmp;
2215
2216 /* TODO: allow to switch the default preference */
2217 catal =
2218 xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
2219 if (catal != NULL) {
2220 if (xmlDefaultXMLCatalogList == NULL)
2221 xmlDefaultXMLCatalogList = catal;
2222 else {
2223 tmp = xmlDefaultXMLCatalogList;
2224 while (tmp->next != NULL)
2225 tmp = tmp->next;
2226 tmp->next = catal;
2227 }
2228 ret = 0;
2229 } else
2230 ret = -1;
Daniel Veillard344cee72001-08-20 00:08:40 +00002231 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002232 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002233 catalNr--;
Daniel Veillard16756b62001-10-01 07:36:25 +00002234 return (ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002235}
2236
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002237/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002238 * xmlLoadCatalogs:
2239 * @paths: a list of file path separated by ':' or spaces
2240 *
2241 * Load the catalogs and makes their definitions effective for the default
2242 * external entity loader.
2243 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002244 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002245 */
2246void
2247xmlLoadCatalogs(const char *pathss) {
2248 const char *cur;
2249 const char *paths;
2250 xmlChar *path;
2251
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002252 if (pathss == NULL)
2253 return;
2254
Daniel Veillard81418e32001-05-22 15:08:55 +00002255 cur = pathss;
2256 while ((cur != NULL) && (*cur != 0)) {
2257 while (IS_BLANK(*cur)) cur++;
2258 if (*cur != 0) {
2259 paths = cur;
2260 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2261 cur++;
2262 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2263 if (path != NULL) {
2264 xmlLoadCatalog((const char *) path);
2265 xmlFree(path);
2266 }
2267 }
2268 while (*cur == ':')
2269 cur++;
2270 }
2271}
2272
Daniel Veillarda7374592001-05-10 14:17:55 +00002273/**
2274 * xmlCatalogCleanup:
2275 *
2276 * Free up all the memory associated with catalogs
2277 */
2278void
2279xmlCatalogCleanup(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002280 if (xmlDebugCatalogs)
2281 xmlGenericError(xmlGenericErrorContext,
2282 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002283 if (xmlCatalogXMLFiles != NULL)
2284 xmlHashFree(xmlCatalogXMLFiles, NULL);
2285 xmlCatalogXMLFiles = NULL;
Daniel Veillardcda96922001-08-21 10:56:31 +00002286 if (xmlDefaultXMLCatalogList != NULL)
2287 xmlFreeCatalogEntryList(xmlDefaultXMLCatalogList);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002288 xmlDefaultXMLCatalogList = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002289 if (xmlDefaultCatalog != NULL)
2290 xmlHashFree(xmlDefaultCatalog,
2291 (xmlHashDeallocator) xmlFreeCatalogEntry);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002292 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002293 xmlDebugCatalogs = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00002294 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002295 xmlCatalogInitialized = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00002296}
2297
2298/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002299 * xmlCatalogGetSystem:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002300 * @pubId: the public ID string
Daniel Veillarda7374592001-05-10 14:17:55 +00002301 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002302 * Try to lookup the system ID associated to a public ID
2303 * DEPRECATED, use xmlCatalogResolveSystem()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002304 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002305 * Returns the system ID if found or NULL otherwise.
Daniel Veillarda7374592001-05-10 14:17:55 +00002306 */
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002307const xmlChar *
2308xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002309 xmlChar *ret;
2310 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002311
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002312 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002313 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002314
2315 if (!xmlCatalogInitialized)
2316 xmlInitializeCatalog();
2317
2318 /*
2319 * Check first the XML catalogs
2320 */
2321 if (xmlDefaultXMLCatalogList != NULL) {
2322 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
2323 if (ret != NULL) {
2324 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
2325 result[sizeof(result) - 1] = 0;
2326 return(result);
2327 }
2328 }
2329
2330 if (xmlDefaultCatalog != NULL)
2331 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID));
2332 return(NULL);
2333}
2334
2335/**
2336 * xmlCatalogResolveSystem:
2337 * @sysId: the public ID string
2338 *
2339 * Try to lookup the catalog resource for a system ID
2340 *
2341 * Returns the system ID if found or NULL otherwise, the value returned
2342 * must be freed by the caller.
2343 */
2344xmlChar *
2345xmlCatalogResolveSystem(const xmlChar *sysID) {
2346 xmlCatalogEntryPtr catal;
2347 xmlChar *ret;
2348 const xmlChar *sgml;
2349
2350 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002351 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002352
2353 if (!xmlCatalogInitialized)
2354 xmlInitializeCatalog();
2355
2356 /*
2357 * Check first the XML catalogs
2358 */
2359 catal = xmlDefaultXMLCatalogList;
2360 if (catal != NULL) {
2361 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
2362 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2363 return(ret);
2364 }
2365
2366 if (xmlDefaultCatalog != NULL) {
2367 sgml = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
2368 if (sgml != NULL)
2369 return(xmlStrdup(sgml));
2370 }
Daniel Veillard344cee72001-08-20 00:08:40 +00002371 return(NULL);
2372}
2373
2374/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002375 * xmlCatalogGetPublic:
2376 * @pubId: the public ID string
2377 *
2378 * Try to lookup the system ID associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002379 * DEPRECATED, use xmlCatalogResolvePublic()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002380 *
2381 * Returns the system ID if found or NULL otherwise.
2382 */
2383const xmlChar *
2384xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002385 xmlChar *ret;
2386 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002387
Daniel Veillard344cee72001-08-20 00:08:40 +00002388 if (pubID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002389 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00002390
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002391 if (!xmlCatalogInitialized)
2392 xmlInitializeCatalog();
2393
2394 /*
2395 * Check first the XML catalogs
2396 */
2397 if (xmlDefaultXMLCatalogList != NULL) {
2398 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2399 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
2400 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
2401 result[sizeof(result) - 1] = 0;
2402 return(result);
2403 }
2404 }
2405
2406 if (xmlDefaultCatalog != NULL)
2407 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
2408 return(NULL);
2409}
2410
2411/**
2412 * xmlCatalogResolvePublic:
2413 * @pubId: the public ID string
2414 *
2415 * Try to lookup the system ID associated to a public ID
2416 *
2417 * Returns the system ID if found or NULL otherwise, the value returned
2418 * must be freed by the caller.
2419 */
2420xmlChar *
2421xmlCatalogResolvePublic(const xmlChar *pubID) {
2422 xmlCatalogEntryPtr catal;
2423 xmlChar *ret;
2424 const xmlChar *sgml;
2425
2426 if (pubID == NULL)
2427 return(NULL);
2428
2429 if (!xmlCatalogInitialized)
2430 xmlInitializeCatalog();
2431
Daniel Veillard344cee72001-08-20 00:08:40 +00002432 /*
2433 * Check first the XML catalogs
2434 */
2435 catal = xmlDefaultXMLCatalogList;
2436 if (catal != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002437 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2438 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
Daniel Veillard344cee72001-08-20 00:08:40 +00002439 return(ret);
2440 }
2441
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002442 if (xmlDefaultCatalog != NULL) {
2443 sgml = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
2444 if (sgml != NULL)
2445 return(xmlStrdup(sgml));
2446 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002447 return(NULL);
2448}
Daniel Veillard344cee72001-08-20 00:08:40 +00002449
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002450/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002451 * xmlCatalogResolve:
2452 * @pubId: the public ID string
2453 * @sysId: the system ID string
2454 *
2455 * Do a complete resolution lookup of an External Identifier
2456 *
2457 * Returns the URI of the resource or NULL if not found, it must be freed
2458 * by the caller.
2459 */
2460xmlChar *
2461xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002462 if ((pubID == NULL) && (sysID == NULL))
2463 return(NULL);
2464
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002465 if (!xmlCatalogInitialized)
2466 xmlInitializeCatalog();
2467
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002468 if (xmlDebugCatalogs) {
2469 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002470 xmlGenericError(xmlGenericErrorContext,
2471 "Resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002472 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002473 xmlGenericError(xmlGenericErrorContext,
2474 "Resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002475 }
2476 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00002477
Daniel Veillardcda96922001-08-21 10:56:31 +00002478 if (xmlDefaultXMLCatalogList != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002479 xmlChar *ret;
2480 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, sysID);
2481 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2482 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002483 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002484 const xmlChar *ret;
2485
2486 ret = xmlCatalogSGMLResolve(pubID, sysID);
2487 if (ret != NULL)
2488 return(xmlStrdup(ret));
Daniel Veillardcda96922001-08-21 10:56:31 +00002489 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002490 return(NULL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002491}
2492
2493/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002494 * xmlCatalogResolveURI:
2495 * @pubId: the URI
2496 *
2497 * Do a complete resolution lookup of an URI
2498 *
2499 * Returns the URI of the resource or NULL if not found, it must be freed
2500 * by the caller.
2501 */
2502xmlChar *
2503xmlCatalogResolveURI(const xmlChar *URI) {
2504 if (!xmlCatalogInitialized)
2505 xmlInitializeCatalog();
2506
Daniel Veillard6990bf32001-08-23 21:17:48 +00002507 if (URI == NULL)
2508 return(NULL);
2509
2510 if (xmlDebugCatalogs)
2511 xmlGenericError(xmlGenericErrorContext,
2512 "Resolve URI %s\n", URI);
2513
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002514 if (xmlDefaultXMLCatalogList != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002515 xmlChar *ret;
2516
2517 ret = xmlCatalogListXMLResolveURI(xmlDefaultXMLCatalogList, URI);
2518 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2519 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002520 } else {
2521 const xmlChar *ret;
2522
2523 ret = xmlCatalogSGMLResolve(NULL, URI);
2524 if (ret != NULL)
2525 return(xmlStrdup(ret));
2526 }
2527 return(NULL);
2528}
2529
2530/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002531 * xmlCatalogDump:
2532 * @out: the file.
2533 *
2534 * Free up all the memory associated with catalogs
2535 */
2536void
2537xmlCatalogDump(FILE *out) {
2538 if (out == NULL)
2539 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00002540
2541 if (xmlDefaultXMLCatalogList != NULL) {
2542 xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList);
2543 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002544 xmlHashScan(xmlDefaultCatalog,
2545 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00002546 }
2547}
2548
2549/**
2550 * xmlCatalogAdd:
2551 * @type: the type of record to add to the catalog
2552 * @orig: the system, public or prefix to match
2553 * @replace: the replacement value for the match
2554 *
2555 * Add an entry in the catalog, it may overwrite existing but
2556 * different entries.
2557 *
2558 * Returns 0 if successful, -1 otherwise
2559 */
2560int
2561xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
2562 int res = -1;
2563
Daniel Veillard82d75332001-10-08 15:01:59 +00002564 if ((xmlDefaultCatalog != NULL) &&
2565 (xmlStrEqual(type, BAD_CAST "sgmlcatalog"))) {
2566 xmlCatalogEntryPtr entry;
2567
2568 entry = xmlNewCatalogEntry(SGML_CATA_CATALOG, replace, NULL,
2569 XML_CATA_PREFER_NONE);
2570 res = xmlHashAddEntry(xmlDefaultCatalog, replace, entry);
2571 return(0);
2572 }
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00002573 if ((xmlDefaultXMLCatalogList == NULL) &&
2574 (xmlStrEqual(type, BAD_CAST "catalog"))) {
2575 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2576 orig, xmlCatalogDefaultPrefer);
2577 return(0);
2578 }
2579
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002580 if (!xmlCatalogInitialized)
2581 xmlInitializeCatalog();
2582
Daniel Veillard344cee72001-08-20 00:08:40 +00002583 if (xmlDefaultXMLCatalogList != NULL) {
2584 res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
2585 } else if (xmlDefaultCatalog != NULL) {
William M. Brack5e1cac12001-09-28 16:19:18 +00002586 xmlCatalogEntryType cattype;
Daniel Veillard344cee72001-08-20 00:08:40 +00002587
William M. Brack5e1cac12001-09-28 16:19:18 +00002588 cattype = xmlGetSGMLCatalogEntryType(type);
2589 if (cattype != XML_CATA_NONE) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002590 xmlCatalogEntryPtr entry;
William M. Brack5e1cac12001-09-28 16:19:18 +00002591 entry = xmlNewCatalogEntry(cattype, orig, replace,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002592 XML_CATA_PREFER_NONE);
Daniel Veillard344cee72001-08-20 00:08:40 +00002593 res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
2594 }
2595 }
2596 return(res);
2597}
2598
2599/**
2600 * xmlCatalogRemove:
2601 * @value: the value to remove
2602 *
2603 * Remove an entry from the catalog
2604 *
Daniel Veillard82d75332001-10-08 15:01:59 +00002605 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00002606 */
2607int
2608xmlCatalogRemove(const xmlChar *value) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002609 int res = -1;
2610
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002611 if (!xmlCatalogInitialized)
2612 xmlInitializeCatalog();
2613
Daniel Veillardcda96922001-08-21 10:56:31 +00002614 if (xmlDefaultXMLCatalogList != NULL) {
2615 res = xmlDelXMLCatalog(xmlDefaultXMLCatalogList, value);
2616 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002617 res = xmlHashRemoveEntry(xmlDefaultCatalog, value,
2618 (xmlHashDeallocator) xmlFreeCatalogEntry);
2619 if (res == 0)
2620 res = 1;
Daniel Veillardcda96922001-08-21 10:56:31 +00002621 }
2622 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00002623}
2624
2625/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002626 * xmlCatalogConvert:
2627 *
2628 * Convert all the SGML catalog entries as XML ones
2629 *
2630 * Returns the number of entries converted if successful, -1 otherwise
2631 */
2632int
2633xmlCatalogConvert(void) {
2634 int res = -1;
2635
2636 if (!xmlCatalogInitialized)
2637 xmlInitializeCatalog();
2638
2639 if (xmlDebugCatalogs) {
2640 xmlGenericError(xmlGenericErrorContext,
2641 "Converting SGML catalog to XML\n");
2642 }
2643
2644 if (xmlDefaultXMLCatalogList == NULL) {
2645 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
2646 NULL, BAD_CAST "NewCatalog.xml",
2647 xmlCatalogDefaultPrefer);
2648 }
2649 if (xmlDefaultCatalog != NULL) {
2650 res = 0;
2651
2652 xmlHashScan(xmlDefaultCatalog,
2653 (xmlHashScanner) xmlCatalogConvertEntry, &res);
2654 }
2655 return(res);
2656}
2657
2658/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002659 * xmlCatalogGetDefaults:
2660 *
2661 * Used to get the user preference w.r.t. to what catalogs should
2662 * be accepted
2663 *
2664 * Returns the current xmlCatalogAllow value
2665 */
2666xmlCatalogAllow
2667xmlCatalogGetDefaults(void) {
2668 return(xmlCatalogDefaultAllow);
2669}
2670
2671/**
2672 * xmlCatalogSetDefaults:
2673 *
2674 * Used to set the user preference w.r.t. to what catalogs should
2675 * be accepted
2676 */
2677void
2678xmlCatalogSetDefaults(xmlCatalogAllow allow) {
2679 if (!xmlCatalogInitialized)
2680 xmlInitializeCatalog();
2681 if (xmlDebugCatalogs) {
2682 switch (allow) {
2683 case XML_CATA_ALLOW_NONE:
2684 xmlGenericError(xmlGenericErrorContext,
2685 "Disabling catalog usage\n");
2686 break;
2687 case XML_CATA_ALLOW_GLOBAL:
2688 xmlGenericError(xmlGenericErrorContext,
2689 "Allowing only global catalogs\n");
2690 break;
2691 case XML_CATA_ALLOW_DOCUMENT:
2692 xmlGenericError(xmlGenericErrorContext,
2693 "Allowing only catalogs from the document\n");
2694 break;
2695 case XML_CATA_ALLOW_ALL:
2696 xmlGenericError(xmlGenericErrorContext,
2697 "Allowing all catalogs\n");
2698 break;
2699 }
2700 }
2701 xmlCatalogDefaultAllow = allow;
2702}
2703
2704/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002705 * xmlCatalogSetDefaultPrefer:
2706 * @prefer: the default preference for delegation
2707 *
2708 * Allows to set the preference between public and system for deletion
2709 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002710 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002711 *
2712 * Returns the previous value of the default preference for delegation
2713 */
2714xmlCatalogPrefer
2715xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
2716 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
2717
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002718 if (!xmlCatalogInitialized)
2719 xmlInitializeCatalog();
2720 if (prefer == XML_CATA_PREFER_NONE)
2721 return(ret);
2722
2723 if (xmlDebugCatalogs) {
2724 switch (prefer) {
2725 case XML_CATA_PREFER_PUBLIC:
2726 xmlGenericError(xmlGenericErrorContext,
2727 "Setting catalog preference to PUBLIC\n");
2728 break;
2729 case XML_CATA_PREFER_SYSTEM:
2730 xmlGenericError(xmlGenericErrorContext,
2731 "Setting catalog preference to SYSTEM\n");
2732 break;
2733 case XML_CATA_PREFER_NONE:
2734 break;
2735 }
2736 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002737 xmlCatalogDefaultPrefer = prefer;
2738 return(ret);
2739}
2740
2741/**
Daniel Veillard344cee72001-08-20 00:08:40 +00002742 * xmlCatalogSetDebug:
2743 * @level: the debug level of catalogs required
2744 *
2745 * Used to set the debug level for catalog operation, 0 disable
2746 * debugging, 1 enable it
2747 *
2748 * Returns the previous value of the catalog debugging level
2749 */
2750int
2751xmlCatalogSetDebug(int level) {
2752 int ret = xmlDebugCatalogs;
2753
2754 if (level <= 0)
2755 xmlDebugCatalogs = 0;
2756 else
2757 xmlDebugCatalogs = level;
2758 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002759}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002760
2761/**
2762 * xmlCatalogFreeLocal:
2763 * @catalogs: a document's list of catalogs
2764 *
2765 * Free up the memory associated to the catalog list
2766 */
2767void
2768xmlCatalogFreeLocal(void *catalogs) {
2769 xmlCatalogEntryPtr catal;
2770
2771 catal = (xmlCatalogEntryPtr) catalogs;
2772 if (catal != NULL)
2773 xmlFreeCatalogEntryList(catal);
2774}
2775
2776
2777/**
2778 * xmlCatalogAddLocal:
2779 * @catalogs: a document's list of catalogs
2780 * @URL: the URL to a new local catalog
2781 *
2782 * Add the new entry to the catalog list
2783 *
2784 * Returns the updated list
2785 */
2786void *
2787xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
2788 xmlCatalogEntryPtr catal, add;
2789
2790 if (!xmlCatalogInitialized)
2791 xmlInitializeCatalog();
2792 if (URL == NULL)
2793 return(catalogs);
2794
2795 if (xmlDebugCatalogs)
2796 xmlGenericError(xmlGenericErrorContext,
2797 "Adding document catalog %s\n", URL);
2798
2799 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
2800 xmlCatalogDefaultPrefer);
2801 if (add == NULL)
2802 return(catalogs);
2803
2804 catal = (xmlCatalogEntryPtr) catalogs;
2805 if (catal == NULL)
2806 return((void *) add);
2807
2808 while (catal->next != NULL)
2809 catal = catal->next;
2810 catal->next = add;
2811 return(catalogs);
2812}
2813
2814/**
2815 * xmlCatalogLocalResolve:
2816 * @catalogs: a document's list of catalogs
2817 * @pubId: the public ID string
2818 * @sysId: the system ID string
2819 *
2820 * Do a complete resolution lookup of an External Identifier using a
2821 * document's private catalog list
2822 *
2823 * Returns the URI of the resource or NULL if not found, it must be freed
2824 * by the caller.
2825 */
2826xmlChar *
2827xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
2828 const xmlChar *sysID) {
2829 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002830 xmlChar *ret;
2831
2832 if ((pubID == NULL) && (sysID == NULL))
2833 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002834
2835 if (!xmlCatalogInitialized)
2836 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00002837
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002838 if (xmlDebugCatalogs) {
2839 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002840 xmlGenericError(xmlGenericErrorContext,
2841 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002842 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002843 xmlGenericError(xmlGenericErrorContext,
2844 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002845 }
2846 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00002847
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002848 catal = (xmlCatalogEntryPtr) catalogs;
2849 if (catal == NULL)
2850 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002851 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
2852 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2853 return(ret);
2854 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002855}
2856
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002857/**
2858 * xmlCatalogLocalResolveURI:
2859 * @catalogs: a document's list of catalogs
2860 * @pubId: the URI
2861 *
2862 * Do a complete resolution lookup of an URI using a
2863 * document's private catalog list
2864 *
2865 * Returns the URI of the resource or NULL if not found, it must be freed
2866 * by the caller.
2867 */
2868xmlChar *
2869xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
2870 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002871 xmlChar *ret;
2872
2873 if (URI == NULL)
2874 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002875
2876 if (!xmlCatalogInitialized)
2877 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00002878
2879 if (xmlDebugCatalogs)
2880 xmlGenericError(xmlGenericErrorContext,
2881 "Resolve URI %s\n", URI);
2882
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002883 catal = (xmlCatalogEntryPtr) catalogs;
2884 if (catal == NULL)
2885 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002886 ret = xmlCatalogListXMLResolveURI(catal, URI);
2887 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2888 return(ret);
2889 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002890}
2891
Daniel Veillarda7374592001-05-10 14:17:55 +00002892#endif /* LIBXML_CATALOG_ENABLED */