blob: d7f6904098af1e60b07d2c663df545e451b899e9 [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 Veillardcda96922001-08-21 10:56:31 +00001722xmlParseSGMLCatalog(const xmlChar *value, const char *file) {
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 Veillardaf86c7f2001-05-21 14:11:26 +00001877 xmlChar *filename;
1878
1879 filename = xmlBuildURI(sysid, base);
1880 if (filename != NULL) {
1881 xmlLoadCatalog((const char *)filename);
1882 xmlFree(filename);
1883 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001884 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001885 /*
1886 * drop anything else we won't handle it
1887 */
1888 if (name != NULL)
1889 xmlFree(name);
1890 if (sysid != NULL)
1891 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001892 }
1893 }
1894 if (base != NULL)
1895 xmlFree(base);
1896 if (cur == NULL)
1897 return(-1);
1898 return(0);
1899}
1900
Daniel Veillardcda96922001-08-21 10:56:31 +00001901/**
1902 * xmlCatalogGetSGMLPublic:
1903 * @catal: an SGML catalog hash
1904 * @pubId: the public ID string
1905 *
1906 * Try to lookup the system ID associated to a public ID
1907 *
1908 * Returns the system ID if found or NULL otherwise.
1909 */
1910static const xmlChar *
1911xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
1912 xmlCatalogEntryPtr entry;
1913
1914 if (catal == NULL)
1915 return(NULL);
1916
1917 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
1918 if (entry == NULL)
1919 return(NULL);
1920 if (entry->type == SGML_CATA_PUBLIC)
1921 return(entry->value);
1922 return(NULL);
1923}
1924
1925/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001926 * xmlCatalogGetSGMLSystem:
1927 * @catal: an SGML catalog hash
1928 * @sysId: the public ID string
1929 *
1930 * Try to lookup the catalog local reference for a system ID
1931 *
1932 * Returns the system ID if found or NULL otherwise.
1933 */
1934static const xmlChar *
1935xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
1936 xmlCatalogEntryPtr entry;
1937
1938 if (catal == NULL)
1939 return(NULL);
1940
1941 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
1942 if (entry == NULL)
1943 return(NULL);
1944 if (entry->type == SGML_CATA_SYSTEM)
1945 return(entry->value);
1946 return(NULL);
1947}
1948
1949/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001950 * xmlCatalogSGMLResolve:
1951 * @pubId: the public ID string
1952 * @sysId: the system ID string
1953 *
1954 * Do a complete resolution lookup of an External Identifier
1955 *
1956 * Returns the URI of the resource or NULL if not found
1957 */
1958static const xmlChar *
1959xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00001960 const xmlChar *ret = NULL;
1961
1962 if (xmlDefaultCatalog == NULL)
1963 return(NULL);
1964
1965 if (pubID != NULL)
1966 ret = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
1967 if (ret != NULL)
1968 return(ret);
1969 if (sysID != NULL)
1970 ret = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00001971 return(NULL);
1972}
1973
Daniel Veillarda7374592001-05-10 14:17:55 +00001974/************************************************************************
1975 * *
1976 * Public interfaces *
1977 * *
1978 ************************************************************************/
1979
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001980/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001981 * xmlInitializeCatalog:
1982 *
1983 * Do the catalog initialization.
1984 * TODO: this function is not thread safe, catalog initialization should
1985 * preferably be done once at startup
1986 */
1987void
1988xmlInitializeCatalog(void) {
1989 const char *catalogs;
1990
1991 if (xmlCatalogInitialized != 0)
1992 return;
1993
1994 if (getenv("XML_DEBUG_CATALOG"))
1995 xmlDebugCatalogs = 1;
1996 if ((xmlDefaultXMLCatalogList == NULL) && (xmlDefaultCatalog == NULL)) {
1997 catalogs = getenv("XML_CATALOG_FILES");
1998 if (catalogs == NULL)
1999 catalogs = XML_DEFAULT_CATALOG;
2000 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
2001 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
2002 }
2003
2004 xmlCatalogInitialized = 1;
2005}
2006
2007/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002008 * xmlLoadCatalog:
2009 * @filename: a file path
2010 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002011 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002012 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002013 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002014 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002015 *
2016 * Returns 0 in case of success -1 in case of error
2017 */
2018int
2019xmlLoadCatalog(const char *filename) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002020 int fd, len, ret, i;
Daniel Veillarda7374592001-05-10 14:17:55 +00002021 struct stat info;
2022 xmlChar *content;
2023
2024 if (filename == NULL)
2025 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002026
Daniel Veillarda7374592001-05-10 14:17:55 +00002027 if (xmlDefaultCatalog == NULL)
2028 xmlDefaultCatalog = xmlHashCreate(20);
2029 if (xmlDefaultCatalog == NULL)
2030 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002031
2032 /*
2033 * Need to be done after ...
2034 */
2035 if (!xmlCatalogInitialized)
2036 xmlInitializeCatalog();
2037
2038#ifdef HAVE_STAT
Daniel Veillarda7374592001-05-10 14:17:55 +00002039 if (stat(filename, &info) < 0)
2040 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002041#endif
Daniel Veillarda7374592001-05-10 14:17:55 +00002042
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002043 /*
2044 * Prevent loops
2045 */
2046 for (i = 0;i < catalNr;i++) {
Daniel Veillard81418e32001-05-22 15:08:55 +00002047 if (xmlStrEqual((const xmlChar *)catalTab[i],
2048 (const xmlChar *)filename)) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002049 xmlGenericError(xmlGenericErrorContext,
2050 "xmlLoadCatalog: %s seems to induce a loop\n",
2051 filename);
2052 return(-1);
2053 }
2054 }
2055 if (catalNr >= catalMax) {
2056 xmlGenericError(xmlGenericErrorContext,
2057 "xmlLoadCatalog: %s catalog list too deep\n",
2058 filename);
2059 return(-1);
2060 }
2061 catalTab[catalNr++] = filename;
2062
2063 if ((fd = open(filename, O_RDONLY)) < 0) {
2064 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00002065 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002066 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002067
2068 content = xmlMalloc(info.st_size + 10);
2069 if (content == NULL) {
2070 xmlGenericError(xmlGenericErrorContext,
2071 "realloc of %d byte failed\n", info.st_size + 10);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002072 catalNr--;
2073 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002074 }
2075 len = read(fd, content, info.st_size);
2076 if (len < 0) {
2077 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002078 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00002079 return(-1);
2080 }
2081 content[len] = 0;
2082 close(fd);
2083
Daniel Veillard344cee72001-08-20 00:08:40 +00002084 if ((content[0] == ' ') || (content[0] == '-') ||
2085 ((content[0] >= 'A') && (content[0] <= 'Z')) ||
2086 ((content[0] >= 'a') && (content[0] <= 'z')))
Daniel Veillardcda96922001-08-21 10:56:31 +00002087 ret = xmlParseSGMLCatalog(content, filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00002088 else {
2089 xmlCatalogEntryPtr catal, tmp;
2090 /* TODO: allow to switch the default preference */
2091 catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
2092 if (catal != NULL) {
2093 if (xmlDefaultXMLCatalogList == NULL)
2094 xmlDefaultXMLCatalogList = catal;
2095 else {
2096 tmp = xmlDefaultXMLCatalogList;
2097 while (tmp->next != NULL)
2098 tmp = tmp->next;
2099 tmp->next = catal;
2100 }
2101 ret = 0;
2102 } else
2103 ret = -1;
2104 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002105 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002106 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00002107 return(ret);
2108}
2109
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002110/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002111 * xmlLoadCatalogs:
2112 * @paths: a list of file path separated by ':' or spaces
2113 *
2114 * Load the catalogs and makes their definitions effective for the default
2115 * external entity loader.
2116 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002117 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002118 */
2119void
2120xmlLoadCatalogs(const char *pathss) {
2121 const char *cur;
2122 const char *paths;
2123 xmlChar *path;
2124
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002125 if (pathss == NULL)
2126 return;
2127
Daniel Veillard81418e32001-05-22 15:08:55 +00002128 cur = pathss;
2129 while ((cur != NULL) && (*cur != 0)) {
2130 while (IS_BLANK(*cur)) cur++;
2131 if (*cur != 0) {
2132 paths = cur;
2133 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2134 cur++;
2135 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2136 if (path != NULL) {
2137 xmlLoadCatalog((const char *) path);
2138 xmlFree(path);
2139 }
2140 }
2141 while (*cur == ':')
2142 cur++;
2143 }
2144}
2145
Daniel Veillarda7374592001-05-10 14:17:55 +00002146/**
2147 * xmlCatalogCleanup:
2148 *
2149 * Free up all the memory associated with catalogs
2150 */
2151void
2152xmlCatalogCleanup(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002153 if (xmlDebugCatalogs)
2154 xmlGenericError(xmlGenericErrorContext,
2155 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002156 if (xmlCatalogXMLFiles != NULL)
2157 xmlHashFree(xmlCatalogXMLFiles, NULL);
2158 xmlCatalogXMLFiles = NULL;
Daniel Veillardcda96922001-08-21 10:56:31 +00002159 if (xmlDefaultXMLCatalogList != NULL)
2160 xmlFreeCatalogEntryList(xmlDefaultXMLCatalogList);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002161 xmlDefaultXMLCatalogList = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002162 if (xmlDefaultCatalog != NULL)
2163 xmlHashFree(xmlDefaultCatalog,
2164 (xmlHashDeallocator) xmlFreeCatalogEntry);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002165 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002166 xmlDebugCatalogs = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00002167 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002168 xmlCatalogInitialized = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00002169}
2170
2171/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002172 * xmlCatalogGetSystem:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002173 * @pubId: the public ID string
Daniel Veillarda7374592001-05-10 14:17:55 +00002174 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002175 * Try to lookup the system ID associated to a public ID
2176 * DEPRECATED, use xmlCatalogResolveSystem()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002177 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002178 * Returns the system ID if found or NULL otherwise.
Daniel Veillarda7374592001-05-10 14:17:55 +00002179 */
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002180const xmlChar *
2181xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002182 xmlChar *ret;
2183 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002184
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002185 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002186 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002187
2188 if (!xmlCatalogInitialized)
2189 xmlInitializeCatalog();
2190
2191 /*
2192 * Check first the XML catalogs
2193 */
2194 if (xmlDefaultXMLCatalogList != NULL) {
2195 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
2196 if (ret != NULL) {
2197 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
2198 result[sizeof(result) - 1] = 0;
2199 return(result);
2200 }
2201 }
2202
2203 if (xmlDefaultCatalog != NULL)
2204 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID));
2205 return(NULL);
2206}
2207
2208/**
2209 * xmlCatalogResolveSystem:
2210 * @sysId: the public ID string
2211 *
2212 * Try to lookup the catalog resource for a system ID
2213 *
2214 * Returns the system ID if found or NULL otherwise, the value returned
2215 * must be freed by the caller.
2216 */
2217xmlChar *
2218xmlCatalogResolveSystem(const xmlChar *sysID) {
2219 xmlCatalogEntryPtr catal;
2220 xmlChar *ret;
2221 const xmlChar *sgml;
2222
2223 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002224 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002225
2226 if (!xmlCatalogInitialized)
2227 xmlInitializeCatalog();
2228
2229 /*
2230 * Check first the XML catalogs
2231 */
2232 catal = xmlDefaultXMLCatalogList;
2233 if (catal != NULL) {
2234 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
2235 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2236 return(ret);
2237 }
2238
2239 if (xmlDefaultCatalog != NULL) {
2240 sgml = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
2241 if (sgml != NULL)
2242 return(xmlStrdup(sgml));
2243 }
Daniel Veillard344cee72001-08-20 00:08:40 +00002244 return(NULL);
2245}
2246
2247/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002248 * xmlCatalogGetPublic:
2249 * @pubId: the public ID string
2250 *
2251 * Try to lookup the system ID associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002252 * DEPRECATED, use xmlCatalogResolvePublic()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002253 *
2254 * Returns the system ID if found or NULL otherwise.
2255 */
2256const xmlChar *
2257xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002258 xmlChar *ret;
2259 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002260
Daniel Veillard344cee72001-08-20 00:08:40 +00002261 if (pubID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002262 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00002263
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002264 if (!xmlCatalogInitialized)
2265 xmlInitializeCatalog();
2266
2267 /*
2268 * Check first the XML catalogs
2269 */
2270 if (xmlDefaultXMLCatalogList != NULL) {
2271 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2272 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
2273 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
2274 result[sizeof(result) - 1] = 0;
2275 return(result);
2276 }
2277 }
2278
2279 if (xmlDefaultCatalog != NULL)
2280 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
2281 return(NULL);
2282}
2283
2284/**
2285 * xmlCatalogResolvePublic:
2286 * @pubId: the public ID string
2287 *
2288 * Try to lookup the system ID associated to a public ID
2289 *
2290 * Returns the system ID if found or NULL otherwise, the value returned
2291 * must be freed by the caller.
2292 */
2293xmlChar *
2294xmlCatalogResolvePublic(const xmlChar *pubID) {
2295 xmlCatalogEntryPtr catal;
2296 xmlChar *ret;
2297 const xmlChar *sgml;
2298
2299 if (pubID == NULL)
2300 return(NULL);
2301
2302 if (!xmlCatalogInitialized)
2303 xmlInitializeCatalog();
2304
Daniel Veillard344cee72001-08-20 00:08:40 +00002305 /*
2306 * Check first the XML catalogs
2307 */
2308 catal = xmlDefaultXMLCatalogList;
2309 if (catal != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002310 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2311 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
Daniel Veillard344cee72001-08-20 00:08:40 +00002312 return(ret);
2313 }
2314
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002315 if (xmlDefaultCatalog != NULL) {
2316 sgml = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
2317 if (sgml != NULL)
2318 return(xmlStrdup(sgml));
2319 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002320 return(NULL);
2321}
Daniel Veillard344cee72001-08-20 00:08:40 +00002322
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002323/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002324 * xmlCatalogResolve:
2325 * @pubId: the public ID string
2326 * @sysId: the system ID string
2327 *
2328 * Do a complete resolution lookup of an External Identifier
2329 *
2330 * Returns the URI of the resource or NULL if not found, it must be freed
2331 * by the caller.
2332 */
2333xmlChar *
2334xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002335 if ((pubID == NULL) && (sysID == NULL))
2336 return(NULL);
2337
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002338 if (!xmlCatalogInitialized)
2339 xmlInitializeCatalog();
2340
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002341 if (xmlDebugCatalogs) {
2342 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002343 xmlGenericError(xmlGenericErrorContext,
2344 "Resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002345 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002346 xmlGenericError(xmlGenericErrorContext,
2347 "Resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002348 }
2349 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00002350
Daniel Veillardcda96922001-08-21 10:56:31 +00002351 if (xmlDefaultXMLCatalogList != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002352 xmlChar *ret;
2353 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, sysID);
2354 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2355 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002356 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002357 const xmlChar *ret;
2358
2359 ret = xmlCatalogSGMLResolve(pubID, sysID);
2360 if (ret != NULL)
2361 return(xmlStrdup(ret));
Daniel Veillardcda96922001-08-21 10:56:31 +00002362 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002363 return(NULL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002364}
2365
2366/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002367 * xmlCatalogResolveURI:
2368 * @pubId: the URI
2369 *
2370 * Do a complete resolution lookup of an URI
2371 *
2372 * Returns the URI of the resource or NULL if not found, it must be freed
2373 * by the caller.
2374 */
2375xmlChar *
2376xmlCatalogResolveURI(const xmlChar *URI) {
2377 if (!xmlCatalogInitialized)
2378 xmlInitializeCatalog();
2379
Daniel Veillard6990bf32001-08-23 21:17:48 +00002380 if (URI == NULL)
2381 return(NULL);
2382
2383 if (xmlDebugCatalogs)
2384 xmlGenericError(xmlGenericErrorContext,
2385 "Resolve URI %s\n", URI);
2386
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002387 if (xmlDefaultXMLCatalogList != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002388 xmlChar *ret;
2389
2390 ret = xmlCatalogListXMLResolveURI(xmlDefaultXMLCatalogList, URI);
2391 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2392 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002393 } else {
2394 const xmlChar *ret;
2395
2396 ret = xmlCatalogSGMLResolve(NULL, URI);
2397 if (ret != NULL)
2398 return(xmlStrdup(ret));
2399 }
2400 return(NULL);
2401}
2402
2403/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002404 * xmlCatalogDump:
2405 * @out: the file.
2406 *
2407 * Free up all the memory associated with catalogs
2408 */
2409void
2410xmlCatalogDump(FILE *out) {
2411 if (out == NULL)
2412 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00002413
2414 if (xmlDefaultXMLCatalogList != NULL) {
2415 xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList);
2416 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002417 xmlHashScan(xmlDefaultCatalog,
2418 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00002419 }
2420}
2421
2422/**
2423 * xmlCatalogAdd:
2424 * @type: the type of record to add to the catalog
2425 * @orig: the system, public or prefix to match
2426 * @replace: the replacement value for the match
2427 *
2428 * Add an entry in the catalog, it may overwrite existing but
2429 * different entries.
2430 *
2431 * Returns 0 if successful, -1 otherwise
2432 */
2433int
2434xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
2435 int res = -1;
2436
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00002437 if ((xmlDefaultXMLCatalogList == NULL) &&
2438 (xmlStrEqual(type, BAD_CAST "catalog"))) {
2439 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2440 orig, xmlCatalogDefaultPrefer);
2441 return(0);
2442 }
2443
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002444 if (!xmlCatalogInitialized)
2445 xmlInitializeCatalog();
2446
Daniel Veillard344cee72001-08-20 00:08:40 +00002447 if (xmlDefaultXMLCatalogList != NULL) {
2448 res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
2449 } else if (xmlDefaultCatalog != NULL) {
William M. Brack5e1cac12001-09-28 16:19:18 +00002450 xmlCatalogEntryType cattype;
Daniel Veillard344cee72001-08-20 00:08:40 +00002451
William M. Brack5e1cac12001-09-28 16:19:18 +00002452 cattype = xmlGetSGMLCatalogEntryType(type);
2453 if (cattype != XML_CATA_NONE) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002454 xmlCatalogEntryPtr entry;
William M. Brack5e1cac12001-09-28 16:19:18 +00002455 entry = xmlNewCatalogEntry(cattype, orig, replace,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002456 XML_CATA_PREFER_NONE);
Daniel Veillard344cee72001-08-20 00:08:40 +00002457 res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
2458 }
2459 }
2460 return(res);
2461}
2462
2463/**
2464 * xmlCatalogRemove:
2465 * @value: the value to remove
2466 *
2467 * Remove an entry from the catalog
2468 *
2469 * Returns 0 if successful, -1 otherwise
2470 */
2471int
2472xmlCatalogRemove(const xmlChar *value) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002473 int res = -1;
2474
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002475 if (!xmlCatalogInitialized)
2476 xmlInitializeCatalog();
2477
Daniel Veillardcda96922001-08-21 10:56:31 +00002478 if (xmlDefaultXMLCatalogList != NULL) {
2479 res = xmlDelXMLCatalog(xmlDefaultXMLCatalogList, value);
2480 } else if (xmlDefaultCatalog != NULL) {
2481 TODO
2482 }
2483 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00002484}
2485
2486/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002487 * xmlCatalogConvert:
2488 *
2489 * Convert all the SGML catalog entries as XML ones
2490 *
2491 * Returns the number of entries converted if successful, -1 otherwise
2492 */
2493int
2494xmlCatalogConvert(void) {
2495 int res = -1;
2496
2497 if (!xmlCatalogInitialized)
2498 xmlInitializeCatalog();
2499
2500 if (xmlDebugCatalogs) {
2501 xmlGenericError(xmlGenericErrorContext,
2502 "Converting SGML catalog to XML\n");
2503 }
2504
2505 if (xmlDefaultXMLCatalogList == NULL) {
2506 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
2507 NULL, BAD_CAST "NewCatalog.xml",
2508 xmlCatalogDefaultPrefer);
2509 }
2510 if (xmlDefaultCatalog != NULL) {
2511 res = 0;
2512
2513 xmlHashScan(xmlDefaultCatalog,
2514 (xmlHashScanner) xmlCatalogConvertEntry, &res);
2515 }
2516 return(res);
2517}
2518
2519/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002520 * xmlCatalogGetDefaults:
2521 *
2522 * Used to get the user preference w.r.t. to what catalogs should
2523 * be accepted
2524 *
2525 * Returns the current xmlCatalogAllow value
2526 */
2527xmlCatalogAllow
2528xmlCatalogGetDefaults(void) {
2529 return(xmlCatalogDefaultAllow);
2530}
2531
2532/**
2533 * xmlCatalogSetDefaults:
2534 *
2535 * Used to set the user preference w.r.t. to what catalogs should
2536 * be accepted
2537 */
2538void
2539xmlCatalogSetDefaults(xmlCatalogAllow allow) {
2540 if (!xmlCatalogInitialized)
2541 xmlInitializeCatalog();
2542 if (xmlDebugCatalogs) {
2543 switch (allow) {
2544 case XML_CATA_ALLOW_NONE:
2545 xmlGenericError(xmlGenericErrorContext,
2546 "Disabling catalog usage\n");
2547 break;
2548 case XML_CATA_ALLOW_GLOBAL:
2549 xmlGenericError(xmlGenericErrorContext,
2550 "Allowing only global catalogs\n");
2551 break;
2552 case XML_CATA_ALLOW_DOCUMENT:
2553 xmlGenericError(xmlGenericErrorContext,
2554 "Allowing only catalogs from the document\n");
2555 break;
2556 case XML_CATA_ALLOW_ALL:
2557 xmlGenericError(xmlGenericErrorContext,
2558 "Allowing all catalogs\n");
2559 break;
2560 }
2561 }
2562 xmlCatalogDefaultAllow = allow;
2563}
2564
2565/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002566 * xmlCatalogSetDefaultPrefer:
2567 * @prefer: the default preference for delegation
2568 *
2569 * Allows to set the preference between public and system for deletion
2570 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002571 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002572 *
2573 * Returns the previous value of the default preference for delegation
2574 */
2575xmlCatalogPrefer
2576xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
2577 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
2578
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002579 if (!xmlCatalogInitialized)
2580 xmlInitializeCatalog();
2581 if (prefer == XML_CATA_PREFER_NONE)
2582 return(ret);
2583
2584 if (xmlDebugCatalogs) {
2585 switch (prefer) {
2586 case XML_CATA_PREFER_PUBLIC:
2587 xmlGenericError(xmlGenericErrorContext,
2588 "Setting catalog preference to PUBLIC\n");
2589 break;
2590 case XML_CATA_PREFER_SYSTEM:
2591 xmlGenericError(xmlGenericErrorContext,
2592 "Setting catalog preference to SYSTEM\n");
2593 break;
2594 case XML_CATA_PREFER_NONE:
2595 break;
2596 }
2597 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002598 xmlCatalogDefaultPrefer = prefer;
2599 return(ret);
2600}
2601
2602/**
Daniel Veillard344cee72001-08-20 00:08:40 +00002603 * xmlCatalogSetDebug:
2604 * @level: the debug level of catalogs required
2605 *
2606 * Used to set the debug level for catalog operation, 0 disable
2607 * debugging, 1 enable it
2608 *
2609 * Returns the previous value of the catalog debugging level
2610 */
2611int
2612xmlCatalogSetDebug(int level) {
2613 int ret = xmlDebugCatalogs;
2614
2615 if (level <= 0)
2616 xmlDebugCatalogs = 0;
2617 else
2618 xmlDebugCatalogs = level;
2619 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002620}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002621
2622/**
2623 * xmlCatalogFreeLocal:
2624 * @catalogs: a document's list of catalogs
2625 *
2626 * Free up the memory associated to the catalog list
2627 */
2628void
2629xmlCatalogFreeLocal(void *catalogs) {
2630 xmlCatalogEntryPtr catal;
2631
2632 catal = (xmlCatalogEntryPtr) catalogs;
2633 if (catal != NULL)
2634 xmlFreeCatalogEntryList(catal);
2635}
2636
2637
2638/**
2639 * xmlCatalogAddLocal:
2640 * @catalogs: a document's list of catalogs
2641 * @URL: the URL to a new local catalog
2642 *
2643 * Add the new entry to the catalog list
2644 *
2645 * Returns the updated list
2646 */
2647void *
2648xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
2649 xmlCatalogEntryPtr catal, add;
2650
2651 if (!xmlCatalogInitialized)
2652 xmlInitializeCatalog();
2653 if (URL == NULL)
2654 return(catalogs);
2655
2656 if (xmlDebugCatalogs)
2657 xmlGenericError(xmlGenericErrorContext,
2658 "Adding document catalog %s\n", URL);
2659
2660 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
2661 xmlCatalogDefaultPrefer);
2662 if (add == NULL)
2663 return(catalogs);
2664
2665 catal = (xmlCatalogEntryPtr) catalogs;
2666 if (catal == NULL)
2667 return((void *) add);
2668
2669 while (catal->next != NULL)
2670 catal = catal->next;
2671 catal->next = add;
2672 return(catalogs);
2673}
2674
2675/**
2676 * xmlCatalogLocalResolve:
2677 * @catalogs: a document's list of catalogs
2678 * @pubId: the public ID string
2679 * @sysId: the system ID string
2680 *
2681 * Do a complete resolution lookup of an External Identifier using a
2682 * document's private catalog list
2683 *
2684 * Returns the URI of the resource or NULL if not found, it must be freed
2685 * by the caller.
2686 */
2687xmlChar *
2688xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
2689 const xmlChar *sysID) {
2690 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002691 xmlChar *ret;
2692
2693 if ((pubID == NULL) && (sysID == NULL))
2694 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002695
2696 if (!xmlCatalogInitialized)
2697 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00002698
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002699 if (xmlDebugCatalogs) {
2700 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002701 xmlGenericError(xmlGenericErrorContext,
2702 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002703 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002704 xmlGenericError(xmlGenericErrorContext,
2705 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002706 }
2707 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00002708
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002709 catal = (xmlCatalogEntryPtr) catalogs;
2710 if (catal == NULL)
2711 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002712 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
2713 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2714 return(ret);
2715 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002716}
2717
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002718/**
2719 * xmlCatalogLocalResolveURI:
2720 * @catalogs: a document's list of catalogs
2721 * @pubId: the URI
2722 *
2723 * Do a complete resolution lookup of an URI using a
2724 * document's private catalog list
2725 *
2726 * Returns the URI of the resource or NULL if not found, it must be freed
2727 * by the caller.
2728 */
2729xmlChar *
2730xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
2731 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002732 xmlChar *ret;
2733
2734 if (URI == NULL)
2735 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002736
2737 if (!xmlCatalogInitialized)
2738 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00002739
2740 if (xmlDebugCatalogs)
2741 xmlGenericError(xmlGenericErrorContext,
2742 "Resolve URI %s\n", URI);
2743
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002744 catal = (xmlCatalogEntryPtr) catalogs;
2745 if (catal == NULL)
2746 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002747 ret = xmlCatalogListXMLResolveURI(catal, URI);
2748 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2749 return(ret);
2750 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002751}
2752
Daniel Veillarda7374592001-05-10 14:17:55 +00002753#endif /* LIBXML_CATALOG_ENABLED */