blob: 734ef77fb6f9805f4db11b133cd6e1114c5f8554 [file] [log] [blame]
Daniel Veillarda7374592001-05-10 14:17:55 +00001/**
2 * catalog.c: set of generic Catalog related routines
3 *
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
6 *
Daniel Veillard344cee72001-08-20 00:08:40 +00007 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
9 *
Daniel Veillarda7374592001-05-10 14:17:55 +000010 * See Copyright for the status of this software.
11 *
12 * Daniel.Veillard@imag.fr
13 */
14
15#include "libxml.h"
16
17#ifdef LIBXML_CATALOG_ENABLED
18#ifdef HAVE_SYS_TYPES_H
19#include <sys/types.h>
20#endif
21#ifdef HAVE_SYS_STAT_H
22#include <sys/stat.h>
23#endif
24#ifdef HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27#ifdef HAVE_FCNTL_H
28#include <fcntl.h>
29#endif
30#include <string.h>
31#include <libxml/xmlmemory.h>
32#include <libxml/hash.h>
33#include <libxml/uri.h>
34#include <libxml/parserInternals.h>
35#include <libxml/catalog.h>
36#include <libxml/xmlerror.h>
37
Daniel Veillard6990bf32001-08-23 21:17:48 +000038#define MAX_DELEGATE 50
39
Daniel Veillard344cee72001-08-20 00:08:40 +000040/**
41 * TODO:
42 *
43 * macro to flag unimplemented blocks
44 */
45#define TODO \
46 xmlGenericError(xmlGenericErrorContext, \
47 "Unimplemented block at %s:%d\n", \
48 __FILE__, __LINE__);
49
Daniel Veillardcda96922001-08-21 10:56:31 +000050#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000051#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000052#ifndef XML_DEFAULT_CATALOG
Daniel Veillarde2940dd2001-08-22 00:06:49 +000053#define XML_DEFAULT_CATALOG "/etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000054#endif
Daniel Veillard344cee72001-08-20 00:08:40 +000055
Daniel Veillarda7374592001-05-10 14:17:55 +000056/************************************************************************
57 * *
58 * Types, all private *
59 * *
60 ************************************************************************/
61
62typedef enum {
63 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000064 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000065 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000066 XML_CATA_NEXT_CATALOG,
67 XML_CATA_PUBLIC,
68 XML_CATA_SYSTEM,
69 XML_CATA_REWRITE_SYSTEM,
70 XML_CATA_DELEGATE_PUBLIC,
71 XML_CATA_DELEGATE_SYSTEM,
72 XML_CATA_URI,
73 XML_CATA_REWRITE_URI,
74 XML_CATA_DELEGATE_URI,
75 SGML_CATA_SYSTEM,
76 SGML_CATA_PUBLIC,
77 SGML_CATA_ENTITY,
78 SGML_CATA_PENTITY,
79 SGML_CATA_DOCTYPE,
80 SGML_CATA_LINKTYPE,
81 SGML_CATA_NOTATION,
82 SGML_CATA_DELEGATE,
83 SGML_CATA_BASE,
84 SGML_CATA_CATALOG,
85 SGML_CATA_DOCUMENT,
86 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000087} xmlCatalogEntryType;
88
89typedef struct _xmlCatalogEntry xmlCatalogEntry;
90typedef xmlCatalogEntry *xmlCatalogEntryPtr;
91struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +000092 struct _xmlCatalogEntry *next;
93 struct _xmlCatalogEntry *parent;
94 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +000095 xmlCatalogEntryType type;
96 xmlChar *name;
97 xmlChar *value;
Daniel Veillarde2940dd2001-08-22 00:06:49 +000098 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +000099 int dealloc;
Daniel Veillarda7374592001-05-10 14:17:55 +0000100};
101
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000102static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000103static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +0000104static xmlHashTablePtr xmlDefaultCatalog;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000105static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard344cee72001-08-20 00:08:40 +0000106static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000107static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000108
Daniel Veillarda7374592001-05-10 14:17:55 +0000109
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000110/* Catalog stack */
Daniel Veillard81418e32001-05-22 15:08:55 +0000111static const char * catalTab[10]; /* stack of catals */
112static int catalNr = 0; /* Number of current catal streams */
113static int catalMax = 10; /* Max number of catal streams */
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000114
Daniel Veillard344cee72001-08-20 00:08:40 +0000115static int xmlDebugCatalogs = 0; /* used for debugging */
116
Daniel Veillarda7374592001-05-10 14:17:55 +0000117/************************************************************************
118 * *
119 * alloc or dealloc *
120 * *
121 ************************************************************************/
122
123static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000124xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000125 const xmlChar *value, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000126 xmlCatalogEntryPtr ret;
127
128 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
129 if (ret == NULL) {
130 xmlGenericError(xmlGenericErrorContext,
131 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
132 return(NULL);
133 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000134 ret->next = NULL;
135 ret->parent = NULL;
136 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000137 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000138 if (name != NULL)
139 ret->name = xmlStrdup(name);
140 else
141 ret->name = NULL;
142 if (value != NULL)
143 ret->value = xmlStrdup(value);
144 else
145 ret->value = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000146 ret->prefer = prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000147 ret->dealloc = 1;
Daniel Veillarda7374592001-05-10 14:17:55 +0000148 return(ret);
149}
150
151static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000152xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
153
154static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000155xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
156 if (ret == NULL)
157 return;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000158 if ((ret->children != NULL) && (ret->dealloc == 1))
Daniel Veillard344cee72001-08-20 00:08:40 +0000159 xmlFreeCatalogEntryList(ret->children);
Daniel Veillarda7374592001-05-10 14:17:55 +0000160 if (ret->name != NULL)
161 xmlFree(ret->name);
162 if (ret->value != NULL)
163 xmlFree(ret->value);
164 xmlFree(ret);
165}
166
Daniel Veillard344cee72001-08-20 00:08:40 +0000167static void
168xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
169 xmlCatalogEntryPtr next;
170
171 while (ret != NULL) {
172 next = ret->next;
173 xmlFreeCatalogEntry(ret);
174 ret = next;
175 }
176}
177
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000178/**
179 * xmlCatalogDumpEntry:
180 * @entry: the
181 * @out: the file.
182 *
183 * Free up all the memory associated with catalogs
184 */
185static void
186xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
187 if ((entry == NULL) || (out == NULL))
188 return;
189 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000190 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000191 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000192 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000193 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000194 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000195 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000196 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000197 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000198 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000199 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000200 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000201 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000202 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000203 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000204 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000205 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000206 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000207 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000208 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000209 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000210 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000211 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000212 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000213 fprintf(out, "SGMLDECL "); break;
214 default:
215 return;
216 }
217 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000218 case SGML_CATA_ENTITY:
219 case SGML_CATA_PENTITY:
220 case SGML_CATA_DOCTYPE:
221 case SGML_CATA_LINKTYPE:
222 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000223 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000224 case SGML_CATA_PUBLIC:
225 case SGML_CATA_SYSTEM:
226 case SGML_CATA_SGMLDECL:
227 case SGML_CATA_DOCUMENT:
228 case SGML_CATA_CATALOG:
229 case SGML_CATA_BASE:
230 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000231 fprintf(out, "\"%s\"", entry->name); break;
232 default:
233 break;
234 }
235 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000236 case SGML_CATA_ENTITY:
237 case SGML_CATA_PENTITY:
238 case SGML_CATA_DOCTYPE:
239 case SGML_CATA_LINKTYPE:
240 case SGML_CATA_NOTATION:
241 case SGML_CATA_PUBLIC:
242 case SGML_CATA_SYSTEM:
243 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000244 fprintf(out, " \"%s\"", entry->value); break;
245 default:
246 break;
247 }
248 fprintf(out, "\n");
249}
250
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000251/**
252 * xmlCatalogConvertEntry:
253 * @entry: the entry
254 * @res: pointer to te number converted
255 *
256 * Free up all the memory associated with catalogs
257 */
258static void
259xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, int *res) {
260 if ((entry == NULL) || (xmlDefaultXMLCatalogList == NULL))
261 return;
262 switch (entry->type) {
263 case SGML_CATA_ENTITY:
264 entry->type = XML_CATA_PUBLIC;
265 break;
266 case SGML_CATA_PENTITY:
267 entry->type = XML_CATA_PUBLIC;
268 break;
269 case SGML_CATA_DOCTYPE:
270 entry->type = XML_CATA_PUBLIC;
271 break;
272 case SGML_CATA_LINKTYPE:
273 entry->type = XML_CATA_PUBLIC;
274 break;
275 case SGML_CATA_NOTATION:
276 entry->type = XML_CATA_PUBLIC;
277 break;
278 case SGML_CATA_PUBLIC:
279 entry->type = XML_CATA_PUBLIC;
280 break;
281 case SGML_CATA_SYSTEM:
282 entry->type = XML_CATA_SYSTEM;
283 break;
284 case SGML_CATA_DELEGATE:
285 entry->type = XML_CATA_DELEGATE_PUBLIC;
286 break;
287 case SGML_CATA_CATALOG:
288 entry->type = XML_CATA_CATALOG;
289 break;
290 default:
291 xmlHashRemoveEntry(xmlDefaultCatalog, entry->name,
292 (xmlHashDeallocator) xmlFreeCatalogEntry);
293 return;
294 }
295 /*
296 * Conversion successful, remove from the SGML catalog
297 * and add it to the default XML one
298 */
299 xmlHashRemoveEntry(xmlDefaultCatalog, entry->name, NULL);
300 entry->parent = xmlDefaultXMLCatalogList;
301 entry->next = NULL;
302 if (xmlDefaultXMLCatalogList->children == NULL)
303 xmlDefaultXMLCatalogList->children = entry;
304 else {
305 xmlCatalogEntryPtr prev;
306
307 prev = xmlDefaultXMLCatalogList->children;
308 while (prev->next != NULL)
309 prev = prev->next;
310 prev->next = entry;
311 }
312 if (res != NULL)
313 (*res)++;
314}
315
Daniel Veillarda7374592001-05-10 14:17:55 +0000316/************************************************************************
317 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000318 * Helper function *
319 * *
320 ************************************************************************/
321
322/**
323 * xmlCatalogUnWrapURN:
324 * @urn: an "urn:publicid:" to unwrapp
325 *
326 * Expand the URN into the equivalent Public Identifier
327 *
328 * Returns the new identifier or NULL, the string must be deallocated
329 * by the caller.
330 */
331static xmlChar *
332xmlCatalogUnWrapURN(const xmlChar *urn) {
333 xmlChar result[2000];
334 unsigned int i = 0;
335
336 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
337 return(NULL);
338 urn += sizeof(XML_URN_PUBID) - 1;
339
340 while (*urn != 0) {
341 if (i > sizeof(result) - 3)
342 break;
343 if (*urn == '+') {
344 result[i++] = ' ';
345 urn++;
346 } else if (*urn == ':') {
347 result[i++] = '/';
348 result[i++] = '/';
349 urn++;
350 } else if (*urn == ';') {
351 result[i++] = ':';
352 result[i++] = ':';
353 urn++;
354 } else if (*urn == '%') {
355 if ((urn[1] == '2') && (urn[1] == 'B'))
356 result[i++] = '+';
357 else if ((urn[1] == '3') && (urn[1] == 'A'))
358 result[i++] = ':';
359 else if ((urn[1] == '2') && (urn[1] == 'F'))
360 result[i++] = '/';
361 else if ((urn[1] == '3') && (urn[1] == 'B'))
362 result[i++] = ';';
363 else if ((urn[1] == '2') && (urn[1] == '7'))
364 result[i++] = '\'';
365 else if ((urn[1] == '3') && (urn[1] == 'F'))
366 result[i++] = '?';
367 else if ((urn[1] == '2') && (urn[1] == '3'))
368 result[i++] = '#';
369 else if ((urn[1] == '2') && (urn[1] == '5'))
370 result[i++] = '%';
371 else {
372 result[i++] = *urn;
373 urn++;
374 continue;
375 }
376 urn += 3;
377 } else {
378 result[i++] = *urn;
379 urn++;
380 }
381 }
382 result[i] = 0;
383
384 return(xmlStrdup(result));
385}
386
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000387/**
388 * xmlParseCatalogFile:
389 * @filename: the filename
390 *
391 * parse an XML file and build a tree. It's like xmlParseFile()
392 * except it bypass all catalog lookups.
393 *
394 * Returns the resulting document tree or NULL in case of error
395 */
396
397xmlDocPtr
398xmlParseCatalogFile(const char *filename) {
399 xmlDocPtr ret;
400 xmlParserCtxtPtr ctxt;
401 char *directory = NULL;
402 xmlParserInputPtr inputStream;
403 xmlParserInputBufferPtr buf;
404
405 ctxt = xmlNewParserCtxt();
406 if (ctxt == NULL) {
407 if (xmlDefaultSAXHandler.error != NULL) {
408 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
409 }
410 return(NULL);
411 }
412
413 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
414 if (buf == NULL) {
415 xmlFreeParserCtxt(ctxt);
416 return(NULL);
417 }
418
419 inputStream = xmlNewInputStream(ctxt);
420 if (inputStream == NULL) {
421 xmlFreeParserCtxt(ctxt);
422 return(NULL);
423 }
424
425 inputStream->filename = xmlMemStrdup(filename);
426 inputStream->buf = buf;
427 inputStream->base = inputStream->buf->buffer->content;
428 inputStream->cur = inputStream->buf->buffer->content;
429 inputStream->end =
430 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
431
432 inputPush(ctxt, inputStream);
433 if ((ctxt->directory == NULL) && (directory == NULL))
434 directory = xmlParserGetDirectory(filename);
435 if ((ctxt->directory == NULL) && (directory != NULL))
436 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000437 ctxt->valid = 0;
438 ctxt->validate = 0;
439 ctxt->loadsubset = 0;
440 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000441
442 xmlParseDocument(ctxt);
443
444 if (ctxt->wellFormed)
445 ret = ctxt->myDoc;
446 else {
447 ret = NULL;
448 xmlFreeDoc(ctxt->myDoc);
449 ctxt->myDoc = NULL;
450 }
451 xmlFreeParserCtxt(ctxt);
452
453 return(ret);
454}
455
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000456/************************************************************************
457 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000458 * The XML Catalog parser *
459 * *
460 ************************************************************************/
461
462static xmlCatalogEntryPtr
463xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000464static xmlCatalogEntryPtr
465xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
466 const char *file);
467static void
468xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
469 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000470static xmlChar *
471xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
472 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000473static xmlChar *
474xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
475
Daniel Veillard344cee72001-08-20 00:08:40 +0000476
477static xmlCatalogEntryType
478xmlGetXMLCatalogEntryType(const xmlChar *name) {
479 xmlCatalogEntryType type = XML_CATA_NONE;
480 if (xmlStrEqual(name, (const xmlChar *) "system"))
481 type = XML_CATA_SYSTEM;
482 else if (xmlStrEqual(name, (const xmlChar *) "public"))
483 type = XML_CATA_PUBLIC;
484 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
485 type = XML_CATA_REWRITE_SYSTEM;
486 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
487 type = XML_CATA_DELEGATE_PUBLIC;
488 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
489 type = XML_CATA_DELEGATE_SYSTEM;
490 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
491 type = XML_CATA_URI;
492 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
493 type = XML_CATA_REWRITE_URI;
494 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
495 type = XML_CATA_DELEGATE_URI;
496 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
497 type = XML_CATA_NEXT_CATALOG;
498 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
499 type = XML_CATA_CATALOG;
500 return(type);
501}
502
503static xmlCatalogEntryPtr
504xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
505 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000506 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000507 int ok = 1;
508 xmlChar *uriValue;
509 xmlChar *nameValue = NULL;
510 xmlChar *base = NULL;
511 xmlChar *URL = NULL;
512 xmlCatalogEntryPtr ret = NULL;
513
514 if (attrName != NULL) {
515 nameValue = xmlGetProp(cur, attrName);
516 if (nameValue == NULL) {
517 xmlGenericError(xmlGenericErrorContext,
518 "%s entry lacks '%s'\n", name, attrName);
519 ok = 0;
520 }
521 }
522 uriValue = xmlGetProp(cur, uriAttrName);
523 if (uriValue == NULL) {
524 xmlGenericError(xmlGenericErrorContext,
525 "%s entry lacks '%s'\n", name, uriAttrName);
526 ok = 0;
527 }
528 if (!ok) {
529 if (nameValue != NULL)
530 xmlFree(nameValue);
531 if (uriValue != NULL)
532 xmlFree(uriValue);
533 return(NULL);
534 }
535
536 base = xmlNodeGetBase(cur->doc, cur);
537 URL = xmlBuildURI(uriValue, base);
538 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000539 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000540 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000541 xmlGenericError(xmlGenericErrorContext,
542 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000543 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000544 xmlGenericError(xmlGenericErrorContext,
545 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000546 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000547 ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000548 } else {
549 xmlGenericError(xmlGenericErrorContext,
550 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
551 }
552 if (nameValue != NULL)
553 xmlFree(nameValue);
554 if (uriValue != NULL)
555 xmlFree(uriValue);
556 if (base != NULL)
557 xmlFree(base);
558 if (URL != NULL)
559 xmlFree(URL);
560 return(ret);
561}
562
563static void
564xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
565 xmlCatalogEntryPtr parent)
566{
567 xmlChar *uri = NULL;
568 xmlChar *URL = NULL;
569 xmlChar *base = NULL;
570 xmlCatalogEntryPtr entry = NULL;
571
572 if (cur == NULL)
573 return;
574 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
575 xmlChar *prop;
576
577 prop = xmlGetProp(cur, BAD_CAST "prefer");
578 if (prop != NULL) {
579 if (xmlStrEqual(prop, BAD_CAST "system")) {
580 prefer = XML_CATA_PREFER_SYSTEM;
581 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
582 prefer = XML_CATA_PREFER_PUBLIC;
583 } else {
584 xmlGenericError(xmlGenericErrorContext,
585 "Invalid value for prefer: '%s'\n", prop);
586 }
587 xmlFree(prop);
588 }
589 /*
590 * Recurse to propagate prefer to the subtree
591 * (xml:base handling is automated)
592 */
593 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
594 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
595 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000596 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000597 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
598 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000599 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000600 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
601 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
602 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000603 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000604 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
605 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
606 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000607 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000608 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
609 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
610 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000611 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000612 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
613 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
614 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000615 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000616 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
617 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
618 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000619 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000620 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
621 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
622 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000623 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000624 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
625 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
626 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000627 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000628 }
629 if ((entry != NULL) && (parent != NULL)) {
630 entry->parent = parent;
631 if (parent->children == NULL)
632 parent->children = entry;
633 else {
634 xmlCatalogEntryPtr prev;
635
636 prev = parent->children;
637 while (prev->next != NULL)
638 prev = prev->next;
639 prev->next = entry;
640 }
641 }
642 if (base != NULL)
643 xmlFree(base);
644 if (uri != NULL)
645 xmlFree(uri);
646 if (URL != NULL)
647 xmlFree(URL);
648}
649
650static void
651xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
652 xmlCatalogEntryPtr parent) {
653 while (cur != NULL) {
654 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
655 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
656 xmlParseXMLCatalogNode(cur, prefer, parent);
657 }
658 cur = cur->next;
659 }
660 /* TODO: sort the list according to REWRITE lengths and prefer value */
661}
662
663static xmlCatalogEntryPtr
664xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
665 const char *file) {
666 xmlDocPtr doc;
667 xmlNodePtr cur;
668 xmlChar *prop;
669 xmlCatalogEntryPtr parent = NULL;
670
671 if ((value == NULL) || (file == NULL))
672 return(NULL);
673
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000674 if (xmlDebugCatalogs)
675 xmlGenericError(xmlGenericErrorContext,
676 "Parsing catalog %s's content\n", file);
677
Daniel Veillard344cee72001-08-20 00:08:40 +0000678 doc = xmlParseDoc((xmlChar *) value);
679 if (doc == NULL)
680 return(NULL);
681 doc->URL = xmlStrdup((const xmlChar *) file);
682
683 cur = xmlDocGetRootElement(doc);
684 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
685 (cur->ns != NULL) && (cur->ns->href != NULL) &&
686 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
687
Daniel Veillard344cee72001-08-20 00:08:40 +0000688 prop = xmlGetProp(cur, BAD_CAST "prefer");
689 if (prop != NULL) {
690 if (xmlStrEqual(prop, BAD_CAST "system")) {
691 prefer = XML_CATA_PREFER_SYSTEM;
692 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
693 prefer = XML_CATA_PREFER_PUBLIC;
694 } else {
695 xmlGenericError(xmlGenericErrorContext,
696 "Invalid value for prefer: '%s'\n",
697 prop);
698 }
699 xmlFree(prop);
700 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000701 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
702 (const xmlChar *)file, prefer);
703 if (parent == NULL) {
704 xmlFreeDoc(doc);
705 return(NULL);
706 }
707
Daniel Veillard344cee72001-08-20 00:08:40 +0000708 cur = cur->children;
709 xmlParseXMLCatalogNodeList(cur, prefer, parent);
710 } else {
711 xmlGenericError(xmlGenericErrorContext,
712 "File %s is not an XML Catalog\n", file);
713 xmlFreeDoc(doc);
714 return(NULL);
715 }
716 xmlFreeDoc(doc);
717 return(parent);
718}
719
720static xmlCatalogEntryPtr
721xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
722 xmlDocPtr doc;
723 xmlNodePtr cur;
724 xmlChar *prop;
725 xmlCatalogEntryPtr parent = NULL;
726
727 if (filename == NULL)
728 return(NULL);
729
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000730 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000731 if (doc == NULL) {
732 if (xmlDebugCatalogs)
733 xmlGenericError(xmlGenericErrorContext,
734 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000735 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000736 }
737
738 if (xmlDebugCatalogs)
739 xmlGenericError(xmlGenericErrorContext,
740 "Parsing catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000741
742 cur = xmlDocGetRootElement(doc);
743 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
744 (cur->ns != NULL) && (cur->ns->href != NULL) &&
745 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
746
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000747 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
748 (const xmlChar *)filename, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000749 if (parent == NULL) {
750 xmlFreeDoc(doc);
751 return(NULL);
752 }
753
754 prop = xmlGetProp(cur, BAD_CAST "prefer");
755 if (prop != NULL) {
756 if (xmlStrEqual(prop, BAD_CAST "system")) {
757 prefer = XML_CATA_PREFER_SYSTEM;
758 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
759 prefer = XML_CATA_PREFER_PUBLIC;
760 } else {
761 xmlGenericError(xmlGenericErrorContext,
762 "Invalid value for prefer: '%s'\n",
763 prop);
764 }
765 xmlFree(prop);
766 }
767 cur = cur->children;
768 xmlParseXMLCatalogNodeList(cur, prefer, parent);
769 } else {
770 xmlGenericError(xmlGenericErrorContext,
771 "File %s is not an XML Catalog\n", filename);
772 xmlFreeDoc(doc);
773 return(NULL);
774 }
775 xmlFreeDoc(doc);
776 return(parent);
777}
778
Daniel Veillardcda96922001-08-21 10:56:31 +0000779/**
780 * xmlFetchXMLCatalogFile:
781 * @catal: an existing but incomplete catalog entry
782 *
783 * Fetch and parse the subcatalog referenced by an entry
784 * It tries to be thread safe but by lack of an atomic test and
785 * set there is a risk of loosing memory.
786 *
787 * Returns 0 in case of success, -1 otherwise
788 */
789static int
790xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard6990bf32001-08-23 21:17:48 +0000791 xmlCatalogEntryPtr children = NULL, doc;
Daniel Veillardcda96922001-08-21 10:56:31 +0000792
793 if (catal == NULL)
794 return(-1);
795 if (catal->value == NULL)
796 return(-1);
797 if (catal->children != NULL)
798 return(-1);
799
Daniel Veillard6990bf32001-08-23 21:17:48 +0000800 if (xmlCatalogXMLFiles != NULL)
801 children = (xmlCatalogEntryPtr)
802 xmlHashLookup(xmlCatalogXMLFiles, catal->value);
803 if (children != NULL) {
804 catal->children = children;
805 catal->dealloc = 0;
806 return(0);
807 }
808
Daniel Veillardcda96922001-08-21 10:56:31 +0000809 /*
810 * Fetch and parse
811 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000812 doc = xmlParseXMLCatalogFile(catal->prefer, catal->value);
813 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000814 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillardcda96922001-08-21 10:56:31 +0000815 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000816 }
Daniel Veillard6990bf32001-08-23 21:17:48 +0000817 if ((catal->type == XML_CATA_CATALOG) &&
818 (doc->type == XML_CATA_CATALOG)) {
819 children = doc->children;
820 doc->children = NULL;
821 xmlFreeCatalogEntryList(doc);
822 } else {
823 children = doc;
824 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000825
826 /*
827 * Where a real test and set would be needed !
828 */
829 if (catal->children == NULL) {
830 catal->children = children;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000831 catal->dealloc = 1;
832 if (xmlCatalogXMLFiles == NULL)
833 xmlCatalogXMLFiles = xmlHashCreate(10);
834 if (xmlCatalogXMLFiles != NULL) {
835 if (children != NULL)
836 xmlHashAddEntry(xmlCatalogXMLFiles, catal->value, children);
837 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000838 } else {
839 /*
840 * Another thread filled it before us
841 */
842 xmlFreeCatalogEntryList(children);
843 }
844 return(0);
845}
846
Daniel Veillard344cee72001-08-20 00:08:40 +0000847static int
848xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
849 int ret;
850 xmlDocPtr doc;
851 xmlNsPtr ns;
852 xmlDtdPtr dtd;
853 xmlNodePtr node, catalog;
854 xmlOutputBufferPtr buf;
855 xmlCatalogEntryPtr cur;
856
857 /*
858 * Rebuild a catalog
859 */
860 doc = xmlNewDoc(NULL);
861 if (doc == NULL)
862 return(-1);
863 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
864 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
865BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
866
867 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
868
869 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
870 if (ns == NULL) {
871 xmlFreeDoc(doc);
872 return(-1);
873 }
874 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
875 if (catalog == NULL) {
876 xmlFreeNs(ns);
877 xmlFreeDoc(doc);
878 return(-1);
879 }
880 catalog->nsDef = ns;
881 xmlAddChild((xmlNodePtr) doc, catalog);
882
883 /*
884 * add all the catalog entries
885 */
886 cur = catal;
887 while (cur != NULL) {
888 switch (cur->type) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000889 case XML_CATA_BROKEN_CATALOG:
Daniel Veillard344cee72001-08-20 00:08:40 +0000890 case XML_CATA_CATALOG:
891 if (cur == catal) {
892 cur = cur->children;
893 continue;
894 }
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000895 break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000896 case XML_CATA_NEXT_CATALOG:
897 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
898 xmlSetProp(node, BAD_CAST "catalog", cur->value);
899 xmlAddChild(catalog, node);
900 break;
901 case XML_CATA_NONE:
902 break;
903 case XML_CATA_PUBLIC:
904 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
905 xmlSetProp(node, BAD_CAST "publicId", cur->name);
906 xmlSetProp(node, BAD_CAST "uri", cur->value);
907 xmlAddChild(catalog, node);
908 break;
909 case XML_CATA_SYSTEM:
910 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
911 xmlSetProp(node, BAD_CAST "systemId", cur->name);
912 xmlSetProp(node, BAD_CAST "uri", cur->value);
913 xmlAddChild(catalog, node);
914 break;
915 case XML_CATA_REWRITE_SYSTEM:
916 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
917 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
918 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
919 xmlAddChild(catalog, node);
920 break;
921 case XML_CATA_DELEGATE_PUBLIC:
922 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
923 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
924 xmlSetProp(node, BAD_CAST "catalog", cur->value);
925 xmlAddChild(catalog, node);
926 break;
927 case XML_CATA_DELEGATE_SYSTEM:
928 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
929 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
930 xmlSetProp(node, BAD_CAST "catalog", cur->value);
931 xmlAddChild(catalog, node);
932 break;
933 case XML_CATA_URI:
934 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
935 xmlSetProp(node, BAD_CAST "name", cur->name);
936 xmlSetProp(node, BAD_CAST "uri", cur->value);
937 xmlAddChild(catalog, node);
938 break;
939 case XML_CATA_REWRITE_URI:
940 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
941 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
942 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
943 xmlAddChild(catalog, node);
944 break;
945 case XML_CATA_DELEGATE_URI:
946 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
947 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
948 xmlSetProp(node, BAD_CAST "catalog", cur->value);
949 xmlAddChild(catalog, node);
950 break;
951 case SGML_CATA_SYSTEM:
952 case SGML_CATA_PUBLIC:
953 case SGML_CATA_ENTITY:
954 case SGML_CATA_PENTITY:
955 case SGML_CATA_DOCTYPE:
956 case SGML_CATA_LINKTYPE:
957 case SGML_CATA_NOTATION:
958 case SGML_CATA_DELEGATE:
959 case SGML_CATA_BASE:
960 case SGML_CATA_CATALOG:
961 case SGML_CATA_DOCUMENT:
962 case SGML_CATA_SGMLDECL:
963 break;
964 }
965 cur = cur->next;
966 }
967
968 /*
969 * reserialize it
970 */
971 buf = xmlOutputBufferCreateFile(out, NULL);
972 if (buf == NULL) {
973 xmlFreeDoc(doc);
974 return(-1);
975 }
976 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
977
978 /*
979 * Free it
980 */
981 xmlFreeDoc(doc);
982
983 return(ret);
984}
985
986/**
987 * xmlAddXMLCatalog:
988 * @catal: top of an XML catalog
989 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +0000990 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +0000991 * @replace: the replacement value for the match
992 *
993 * Add an entry in the XML catalog, it may overwrite existing but
994 * different entries.
995 *
996 * Returns 0 if successful, -1 otherwise
997 */
998static int
999xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1000 const xmlChar *orig, const xmlChar *replace) {
1001 xmlCatalogEntryPtr cur;
1002 xmlCatalogEntryType typ;
1003
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001004 if ((catal == NULL) ||
1005 ((catal->type != XML_CATA_CATALOG) &&
1006 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001007 return(-1);
1008 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001009 if (typ == XML_CATA_NONE) {
1010 if (xmlDebugCatalogs)
1011 xmlGenericError(xmlGenericErrorContext,
1012 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001013 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001014 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001015
1016 cur = catal->children;
1017 /*
1018 * Might be a simple "update in place"
1019 */
1020 if (cur != NULL) {
1021 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001022 if ((orig != NULL) && (cur->type == typ) &&
1023 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001024 if (xmlDebugCatalogs)
1025 xmlGenericError(xmlGenericErrorContext,
1026 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001027 if (cur->value != NULL)
1028 xmlFree(cur->value);
1029 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001030 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001031 }
1032 if (cur->next == NULL)
1033 break;
1034 cur = cur->next;
1035 }
1036 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001037 if (xmlDebugCatalogs)
1038 xmlGenericError(xmlGenericErrorContext,
1039 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001040 if (cur == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001041 catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +00001042 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001043 cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillardcda96922001-08-21 10:56:31 +00001044 return(0);
1045}
1046
1047/**
1048 * xmlDelXMLCatalog:
1049 * @catal: top of an XML catalog
1050 * @value: the value to remove from teh catalog
1051 *
1052 * Remove entries in the XML catalog where the value or the URI
1053 * is equal to @value
1054 *
1055 * Returns the number of entries removed if successful, -1 otherwise
1056 */
1057static int
1058xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1059 xmlCatalogEntryPtr cur, prev, tmp;
1060 int ret = 0;
1061
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001062 if ((catal == NULL) ||
1063 ((catal->type != XML_CATA_CATALOG) &&
1064 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001065 return(-1);
1066 if (value == NULL)
1067 return(-1);
1068
1069 /*
1070 * Scan the children
1071 */
1072 cur = catal->children;
1073 prev = NULL;
1074 while (cur != NULL) {
1075 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1076 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001077 if (xmlDebugCatalogs) {
1078 if (cur->name != NULL)
1079 xmlGenericError(xmlGenericErrorContext,
1080 "Removing element %s from catalog\n", cur->name);
1081 else
1082 xmlGenericError(xmlGenericErrorContext,
1083 "Removing element %s from catalog\n", cur->value);
1084 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001085 ret++;
1086 tmp = cur;
1087 cur = tmp->next;
1088 if (prev == NULL) {
1089 catal->children = cur;
1090 } else {
1091 prev->next = cur;
1092 }
1093 xmlFreeCatalogEntry(tmp);
1094 continue;
1095 }
1096 prev = cur;
1097 cur = cur->next;
1098 }
1099 return(ret);
1100}
1101
1102/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001103 * xmlCatalogXMLResolve:
1104 * @catal: a catalog list
1105 * @pubId: the public ID string
1106 * @sysId: the system ID string
1107 *
1108 * Do a complete resolution lookup of an External Identifier for a
1109 * list of catalog entries.
1110 *
1111 * Implements (or tries to) 7.1. External Identifier Resolution
1112 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1113 *
1114 * Returns the URI of the resource or NULL if not found
1115 */
1116static xmlChar *
1117xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1118 const xmlChar *sysID) {
1119 xmlChar *ret = NULL;
1120 xmlCatalogEntryPtr cur;
1121 int haveDelegate = 0;
1122 int haveNext = 0;
1123
1124 /*
1125 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1126 */
1127 if (sysID != NULL) {
1128 xmlCatalogEntryPtr rewrite = NULL;
1129 int lenrewrite = 0, len;
1130 cur = catal;
1131 haveDelegate = 0;
1132 while (cur != NULL) {
1133 switch (cur->type) {
1134 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001135 if (xmlStrEqual(sysID, cur->name)) {
1136 if (xmlDebugCatalogs)
1137 xmlGenericError(xmlGenericErrorContext,
1138 "Found system match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001139 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001140 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001141 break;
1142 case XML_CATA_REWRITE_SYSTEM:
1143 len = xmlStrlen(cur->name);
1144 if ((len > lenrewrite) &&
1145 (!xmlStrncmp(sysID, cur->name, len))) {
1146 lenrewrite = len;
1147 rewrite = cur;
1148 }
1149 break;
1150 case XML_CATA_DELEGATE_SYSTEM:
1151 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1152 haveDelegate++;
1153 break;
1154 case XML_CATA_NEXT_CATALOG:
1155 haveNext++;
1156 break;
1157 default:
1158 break;
1159 }
1160 cur = cur->next;
1161 }
1162 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001163 if (xmlDebugCatalogs)
1164 xmlGenericError(xmlGenericErrorContext,
1165 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001166 ret = xmlStrdup(rewrite->value);
1167 if (ret != NULL)
1168 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1169 return(ret);
1170 }
1171 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001172 const xmlChar *delegates[MAX_DELEGATE];
1173 int nbList = 0, i;
1174
Daniel Veillardcda96922001-08-21 10:56:31 +00001175 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001176 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001177 * matches when the list was produced.
1178 */
1179 cur = catal;
1180 while (cur != NULL) {
1181 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1182 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001183 for (i = 0;i < nbList;i++)
1184 if (xmlStrEqual(cur->value, delegates[i]))
1185 break;
1186 if (i < nbList) {
1187 cur = cur->next;
1188 continue;
1189 }
1190 if (nbList < MAX_DELEGATE)
1191 delegates[nbList++] = cur->value;
1192
Daniel Veillardcda96922001-08-21 10:56:31 +00001193 if (cur->children == NULL) {
1194 xmlFetchXMLCatalogFile(cur);
1195 }
1196 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001197 if (xmlDebugCatalogs)
1198 xmlGenericError(xmlGenericErrorContext,
1199 "Trying system delegate %s\n", cur->value);
1200 ret = xmlCatalogListXMLResolve(cur->children, NULL,
1201 sysID);
1202 if (ret != NULL)
1203 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001204 }
1205 }
1206 cur = cur->next;
1207 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001208 /*
1209 * Apply the cut algorithm explained in 4/
1210 */
1211 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001212 }
1213 }
1214 /*
1215 * Then tries 5/ 6/ if a public ID is provided
1216 */
1217 if (pubID != NULL) {
1218 cur = catal;
1219 haveDelegate = 0;
1220 while (cur != NULL) {
1221 switch (cur->type) {
1222 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001223 if (xmlStrEqual(pubID, cur->name)) {
1224 if (xmlDebugCatalogs)
1225 xmlGenericError(xmlGenericErrorContext,
1226 "Found public match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001227 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001228 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001229 break;
1230 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001231 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1232 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001233 haveDelegate++;
1234 break;
1235 case XML_CATA_NEXT_CATALOG:
1236 if (sysID == NULL)
1237 haveNext++;
1238 break;
1239 default:
1240 break;
1241 }
1242 cur = cur->next;
1243 }
1244 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001245 const xmlChar *delegates[MAX_DELEGATE];
1246 int nbList = 0, i;
1247
Daniel Veillardcda96922001-08-21 10:56:31 +00001248 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001249 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001250 * matches when the list was produced.
1251 */
1252 cur = catal;
1253 while (cur != NULL) {
1254 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001255 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1256 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001257
1258 for (i = 0;i < nbList;i++)
1259 if (xmlStrEqual(cur->value, delegates[i]))
1260 break;
1261 if (i < nbList) {
1262 cur = cur->next;
1263 continue;
1264 }
1265 if (nbList < MAX_DELEGATE)
1266 delegates[nbList++] = cur->value;
1267
Daniel Veillardcda96922001-08-21 10:56:31 +00001268 if (cur->children == NULL) {
1269 xmlFetchXMLCatalogFile(cur);
1270 }
1271 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001272 if (xmlDebugCatalogs)
1273 xmlGenericError(xmlGenericErrorContext,
1274 "Trying public delegate %s\n", cur->value);
1275 ret = xmlCatalogListXMLResolve(cur->children, pubID,
1276 NULL);
1277 if (ret != NULL)
1278 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001279 }
1280 }
1281 cur = cur->next;
1282 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001283 /*
1284 * Apply the cut algorithm explained in 4/
1285 */
1286 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001287 }
1288 }
1289 if (haveNext) {
1290 cur = catal;
1291 while (cur != NULL) {
1292 if (cur->type == XML_CATA_NEXT_CATALOG) {
1293 if (cur->children == NULL) {
1294 xmlFetchXMLCatalogFile(cur);
1295 }
1296 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001297 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1298 if (ret != NULL)
1299 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001300 }
1301 }
1302 cur = cur->next;
1303 }
1304 }
1305
1306 return(NULL);
1307}
1308
1309/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001310 * xmlCatalogXMLResolveURI:
1311 * @catal: a catalog list
1312 * @URI: the URI
1313 * @sysId: the system ID string
1314 *
1315 * Do a complete resolution lookup of an External Identifier for a
1316 * list of catalog entries.
1317 *
1318 * Implements (or tries to) 7.2.2. URI Resolution
1319 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1320 *
1321 * Returns the URI of the resource or NULL if not found
1322 */
1323static xmlChar *
1324xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1325 xmlChar *ret = NULL;
1326 xmlCatalogEntryPtr cur;
1327 int haveDelegate = 0;
1328 int haveNext = 0;
1329 xmlCatalogEntryPtr rewrite = NULL;
1330 int lenrewrite = 0, len;
1331
1332 if (catal == NULL)
1333 return(NULL);
1334
1335 if (URI == NULL)
1336 return(NULL);
1337
1338 /*
1339 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1340 */
1341 cur = catal;
1342 haveDelegate = 0;
1343 while (cur != NULL) {
1344 switch (cur->type) {
1345 case XML_CATA_URI:
1346 if (xmlStrEqual(URI, cur->name)) {
1347 if (xmlDebugCatalogs)
1348 xmlGenericError(xmlGenericErrorContext,
1349 "Found URI match %s\n", cur->name);
1350 return(xmlStrdup(cur->value));
1351 }
1352 break;
1353 case XML_CATA_REWRITE_URI:
1354 len = xmlStrlen(cur->name);
1355 if ((len > lenrewrite) &&
1356 (!xmlStrncmp(URI, cur->name, len))) {
1357 lenrewrite = len;
1358 rewrite = cur;
1359 }
1360 break;
1361 case XML_CATA_DELEGATE_URI:
1362 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1363 haveDelegate++;
1364 break;
1365 case XML_CATA_NEXT_CATALOG:
1366 haveNext++;
1367 break;
1368 default:
1369 break;
1370 }
1371 cur = cur->next;
1372 }
1373 if (rewrite != NULL) {
1374 if (xmlDebugCatalogs)
1375 xmlGenericError(xmlGenericErrorContext,
1376 "Using rewriting rule %s\n", rewrite->name);
1377 ret = xmlStrdup(rewrite->value);
1378 if (ret != NULL)
1379 ret = xmlStrcat(ret, &URI[lenrewrite]);
1380 return(ret);
1381 }
1382 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001383 const xmlChar *delegates[MAX_DELEGATE];
1384 int nbList = 0, i;
1385
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001386 /*
1387 * Assume the entries have been sorted by decreasing substring
1388 * matches when the list was produced.
1389 */
1390 cur = catal;
1391 while (cur != NULL) {
1392 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1393 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001394 for (i = 0;i < nbList;i++)
1395 if (xmlStrEqual(cur->value, delegates[i]))
1396 break;
1397 if (i < nbList) {
1398 cur = cur->next;
1399 continue;
1400 }
1401 if (nbList < MAX_DELEGATE)
1402 delegates[nbList++] = cur->value;
1403
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001404 if (cur->children == NULL) {
1405 xmlFetchXMLCatalogFile(cur);
1406 }
1407 if (cur->children != NULL) {
1408 if (xmlDebugCatalogs)
1409 xmlGenericError(xmlGenericErrorContext,
1410 "Trying URI delegate %s\n", cur->value);
1411 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1412 if (ret != NULL)
1413 return(ret);
1414 }
1415 }
1416 cur = cur->next;
1417 }
1418 /*
1419 * Apply the cut algorithm explained in 4/
1420 */
1421 return(XML_CATAL_BREAK);
1422 }
1423 if (haveNext) {
1424 cur = catal;
1425 while (cur != NULL) {
1426 if (cur->type == XML_CATA_NEXT_CATALOG) {
1427 if (cur->children == NULL) {
1428 xmlFetchXMLCatalogFile(cur);
1429 }
1430 if (cur->children != NULL) {
1431 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1432 if (ret != NULL)
1433 return(ret);
1434 }
1435 }
1436 cur = cur->next;
1437 }
1438 }
1439
1440 return(NULL);
1441}
1442
1443/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001444 * xmlCatalogListXMLResolve:
1445 * @catal: a catalog list
1446 * @pubId: the public ID string
1447 * @sysId: the system ID string
1448 *
1449 * Do a complete resolution lookup of an External Identifier for a
1450 * list of catalogs
1451 *
1452 * Implements (or tries to) 7.1. External Identifier Resolution
1453 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1454 *
1455 * Returns the URI of the resource or NULL if not found
1456 */
1457static xmlChar *
1458xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1459 const xmlChar *sysID) {
1460 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001461 xmlChar *urnID = NULL;
1462
1463 if (catal == NULL)
1464 return(NULL);
1465 if ((pubID == NULL) && (sysID == NULL))
1466 return(NULL);
1467
1468 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1469 urnID = xmlCatalogUnWrapURN(pubID);
1470 if (xmlDebugCatalogs) {
1471 if (urnID == NULL)
1472 xmlGenericError(xmlGenericErrorContext,
1473 "Public URN ID %s expanded to NULL\n", pubID);
1474 else
1475 xmlGenericError(xmlGenericErrorContext,
1476 "Public URN ID expanded to %s\n", urnID);
1477 }
1478 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1479 if (urnID != NULL)
1480 xmlFree(urnID);
1481 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001482 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001483 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1484 urnID = xmlCatalogUnWrapURN(sysID);
1485 if (xmlDebugCatalogs) {
1486 if (urnID == NULL)
1487 xmlGenericError(xmlGenericErrorContext,
1488 "System URN ID %s expanded to NULL\n", sysID);
1489 else
1490 xmlGenericError(xmlGenericErrorContext,
1491 "System URN ID expanded to %s\n", urnID);
1492 }
1493 if (pubID == NULL)
1494 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1495 else if (xmlStrEqual(pubID, urnID))
1496 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1497 else {
1498 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1499 }
1500 if (urnID != NULL)
1501 xmlFree(urnID);
1502 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001503 }
1504 while (catal != NULL) {
1505 if (catal->type == XML_CATA_CATALOG) {
1506 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001507 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001508 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001509 if (catal->children != NULL) {
1510 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1511 if (ret != NULL)
1512 return(ret);
1513 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001514 }
1515 catal = catal->next;
1516 }
1517 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001518}
1519
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001520/**
1521 * xmlCatalogListXMLResolveURI:
1522 * @catal: a catalog list
1523 * @URI: the URI
1524 *
1525 * Do a complete resolution lookup of an URI for a list of catalogs
1526 *
1527 * Implements (or tries to) 7.2. URI Resolution
1528 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1529 *
1530 * Returns the URI of the resource or NULL if not found
1531 */
1532static xmlChar *
1533xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1534 xmlChar *ret = NULL;
1535 xmlChar *urnID = NULL;
1536
1537 if (catal == NULL)
1538 return(NULL);
1539 if (URI == NULL)
1540 return(NULL);
1541
1542 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1543 urnID = xmlCatalogUnWrapURN(URI);
1544 if (xmlDebugCatalogs) {
1545 if (urnID == NULL)
1546 xmlGenericError(xmlGenericErrorContext,
1547 "URN ID %s expanded to NULL\n", URI);
1548 else
1549 xmlGenericError(xmlGenericErrorContext,
1550 "URN ID expanded to %s\n", urnID);
1551 }
1552 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1553 if (urnID != NULL)
1554 xmlFree(urnID);
1555 return(ret);
1556 }
1557 while (catal != NULL) {
1558 if (catal->type == XML_CATA_CATALOG) {
1559 if (catal->children == NULL) {
1560 xmlFetchXMLCatalogFile(catal);
1561 }
1562 if (catal->children != NULL) {
1563 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1564 if (ret != NULL)
1565 return(ret);
1566 }
1567 }
1568 catal = catal->next;
1569 }
1570 return(ret);
1571}
1572
Daniel Veillard344cee72001-08-20 00:08:40 +00001573/************************************************************************
1574 * *
1575 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001576 * *
1577 ************************************************************************/
1578
1579
1580#define RAW *cur
1581#define NEXT cur++;
1582#define SKIP(x) cur += x;
1583
1584#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1585
1586static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001587xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001588 if ((cur[0] != '-') || (cur[1] != '-'))
1589 return(cur);
1590 SKIP(2);
1591 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1592 NEXT;
1593 if (cur[0] == 0) {
1594 return(NULL);
1595 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001596 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001597}
1598
1599static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001600xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001601 xmlChar *buf = NULL;
1602 int len = 0;
1603 int size = 50;
1604 xmlChar stop;
1605 int count = 0;
1606
1607 *id = NULL;
1608
1609 if (RAW == '"') {
1610 NEXT;
1611 stop = '"';
1612 } else if (RAW == '\'') {
1613 NEXT;
1614 stop = '\'';
1615 } else {
1616 stop = ' ';
1617 }
1618 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1619 if (buf == NULL) {
1620 xmlGenericError(xmlGenericErrorContext,
1621 "malloc of %d byte failed\n", size);
1622 return(NULL);
1623 }
1624 while (xmlIsPubidChar(*cur)) {
1625 if ((*cur == stop) && (stop != ' '))
1626 break;
1627 if ((stop == ' ') && (IS_BLANK(*cur)))
1628 break;
1629 if (len + 1 >= size) {
1630 size *= 2;
1631 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1632 if (buf == NULL) {
1633 xmlGenericError(xmlGenericErrorContext,
1634 "realloc of %d byte failed\n", size);
1635 return(NULL);
1636 }
1637 }
1638 buf[len++] = *cur;
1639 count++;
1640 NEXT;
1641 }
1642 buf[len] = 0;
1643 if (stop == ' ') {
1644 if (!IS_BLANK(*cur)) {
1645 xmlFree(buf);
1646 return(NULL);
1647 }
1648 } else {
1649 if (*cur != stop) {
1650 xmlFree(buf);
1651 return(NULL);
1652 }
1653 NEXT;
1654 }
1655 *id = buf;
1656 return(cur);
1657}
1658
1659static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001660xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001661 xmlChar buf[XML_MAX_NAMELEN + 5];
1662 int len = 0;
1663 int c;
1664
1665 *name = NULL;
1666
1667 /*
1668 * Handler for more complex cases
1669 */
1670 c = *cur;
1671 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
1672 return(NULL);
1673 }
1674
1675 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
1676 (c == '.') || (c == '-') ||
1677 (c == '_') || (c == ':'))) {
1678 buf[len++] = c;
1679 cur++;
1680 c = *cur;
1681 if (len >= XML_MAX_NAMELEN)
1682 return(NULL);
1683 }
1684 *name = xmlStrndup(buf, len);
1685 return(cur);
1686}
1687
Daniel Veillard344cee72001-08-20 00:08:40 +00001688static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00001689xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001690 xmlCatalogEntryType type = XML_CATA_NONE;
1691 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
1692 type = SGML_CATA_SYSTEM;
1693 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
1694 type = SGML_CATA_PUBLIC;
1695 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1696 type = SGML_CATA_DELEGATE;
1697 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
1698 type = SGML_CATA_ENTITY;
1699 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
1700 type = SGML_CATA_DOCTYPE;
1701 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
1702 type = SGML_CATA_LINKTYPE;
1703 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
1704 type = SGML_CATA_NOTATION;
1705 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
1706 type = SGML_CATA_SGMLDECL;
1707 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
1708 type = SGML_CATA_DOCUMENT;
1709 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
1710 type = SGML_CATA_CATALOG;
1711 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
1712 type = SGML_CATA_BASE;
1713 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1714 type = SGML_CATA_DELEGATE;
1715 return(type);
1716}
1717
Daniel Veillarda7374592001-05-10 14:17:55 +00001718static int
Daniel Veillardcda96922001-08-21 10:56:31 +00001719xmlParseSGMLCatalog(const xmlChar *value, const char *file) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001720 const xmlChar *cur = value;
1721 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001722 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00001723
1724 if ((cur == NULL) || (file == NULL))
1725 return(-1);
1726 base = xmlStrdup((const xmlChar *) file);
1727
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00001728 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001729 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00001730 if (cur[0] == 0)
1731 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00001732 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001733 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00001734 if (cur == NULL) {
1735 /* error */
1736 break;
1737 }
1738 } else {
1739 xmlChar *sysid = NULL;
1740 xmlChar *name = NULL;
1741 xmlCatalogEntryType type = XML_CATA_NONE;
1742
Daniel Veillardcda96922001-08-21 10:56:31 +00001743 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001744 if (name == NULL) {
1745 /* error */
1746 break;
1747 }
1748 if (!IS_BLANK(*cur)) {
1749 /* error */
1750 break;
1751 }
1752 SKIP_BLANKS;
1753 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001754 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00001755 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001756 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00001757 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001758 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001759 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001760 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00001761 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001762 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001763 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001764 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001765 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001766 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00001767 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001768 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001769 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001770 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00001771 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001772 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00001773 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001774 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001775 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001776 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001777 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
1778 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001779 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001780 if (name == NULL) {
1781 /* error */
1782 break;
1783 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001784 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001785 continue;
1786 }
1787 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001788 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001789
1790 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001791 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00001792 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00001793 type = SGML_CATA_PENTITY;
1794 case SGML_CATA_PENTITY:
1795 case SGML_CATA_DOCTYPE:
1796 case SGML_CATA_LINKTYPE:
1797 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00001798 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001799 if (cur == NULL) {
1800 /* error */
1801 break;
1802 }
1803 if (!IS_BLANK(*cur)) {
1804 /* error */
1805 break;
1806 }
1807 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001808 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001809 if (cur == NULL) {
1810 /* error */
1811 break;
1812 }
1813 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001814 case SGML_CATA_PUBLIC:
1815 case SGML_CATA_SYSTEM:
1816 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00001817 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001818 if (cur == NULL) {
1819 /* error */
1820 break;
1821 }
1822 if (!IS_BLANK(*cur)) {
1823 /* error */
1824 break;
1825 }
1826 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001827 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001828 if (cur == NULL) {
1829 /* error */
1830 break;
1831 }
1832 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001833 case SGML_CATA_BASE:
1834 case SGML_CATA_CATALOG:
1835 case SGML_CATA_DOCUMENT:
1836 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00001837 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001838 if (cur == NULL) {
1839 /* error */
1840 break;
1841 }
1842 break;
1843 default:
1844 break;
1845 }
1846 if (cur == NULL) {
1847 if (name != NULL)
1848 xmlFree(name);
1849 if (sysid != NULL)
1850 xmlFree(sysid);
1851 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001852 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001853 if (base != NULL)
1854 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001855 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00001856 } else if ((type == SGML_CATA_PUBLIC) ||
1857 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001858 xmlChar *filename;
1859
1860 filename = xmlBuildURI(sysid, base);
1861 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001862 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00001863
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001864 entry = xmlNewCatalogEntry(type, name, filename,
1865 XML_CATA_PREFER_NONE);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001866 res = xmlHashAddEntry(xmlDefaultCatalog, name, entry);
1867 if (res < 0) {
1868 xmlFreeCatalogEntry(entry);
1869 }
1870 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00001871 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001872
Daniel Veillard344cee72001-08-20 00:08:40 +00001873 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001874 xmlChar *filename;
1875
1876 filename = xmlBuildURI(sysid, base);
1877 if (filename != NULL) {
1878 xmlLoadCatalog((const char *)filename);
1879 xmlFree(filename);
1880 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001881 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001882 /*
1883 * drop anything else we won't handle it
1884 */
1885 if (name != NULL)
1886 xmlFree(name);
1887 if (sysid != NULL)
1888 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001889 }
1890 }
1891 if (base != NULL)
1892 xmlFree(base);
1893 if (cur == NULL)
1894 return(-1);
1895 return(0);
1896}
1897
Daniel Veillardcda96922001-08-21 10:56:31 +00001898/**
1899 * xmlCatalogGetSGMLPublic:
1900 * @catal: an SGML catalog hash
1901 * @pubId: the public ID string
1902 *
1903 * Try to lookup the system ID associated to a public ID
1904 *
1905 * Returns the system ID if found or NULL otherwise.
1906 */
1907static const xmlChar *
1908xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
1909 xmlCatalogEntryPtr entry;
1910
1911 if (catal == NULL)
1912 return(NULL);
1913
1914 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
1915 if (entry == NULL)
1916 return(NULL);
1917 if (entry->type == SGML_CATA_PUBLIC)
1918 return(entry->value);
1919 return(NULL);
1920}
1921
1922/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001923 * xmlCatalogGetSGMLSystem:
1924 * @catal: an SGML catalog hash
1925 * @sysId: the public ID string
1926 *
1927 * Try to lookup the catalog local reference for a system ID
1928 *
1929 * Returns the system ID if found or NULL otherwise.
1930 */
1931static const xmlChar *
1932xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
1933 xmlCatalogEntryPtr entry;
1934
1935 if (catal == NULL)
1936 return(NULL);
1937
1938 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
1939 if (entry == NULL)
1940 return(NULL);
1941 if (entry->type == SGML_CATA_SYSTEM)
1942 return(entry->value);
1943 return(NULL);
1944}
1945
1946/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001947 * xmlCatalogSGMLResolve:
1948 * @pubId: the public ID string
1949 * @sysId: the system ID string
1950 *
1951 * Do a complete resolution lookup of an External Identifier
1952 *
1953 * Returns the URI of the resource or NULL if not found
1954 */
1955static const xmlChar *
1956xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00001957 const xmlChar *ret = NULL;
1958
1959 if (xmlDefaultCatalog == NULL)
1960 return(NULL);
1961
1962 if (pubID != NULL)
1963 ret = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
1964 if (ret != NULL)
1965 return(ret);
1966 if (sysID != NULL)
1967 ret = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00001968 return(NULL);
1969}
1970
Daniel Veillarda7374592001-05-10 14:17:55 +00001971/************************************************************************
1972 * *
1973 * Public interfaces *
1974 * *
1975 ************************************************************************/
1976
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001977/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001978 * xmlInitializeCatalog:
1979 *
1980 * Do the catalog initialization.
1981 * TODO: this function is not thread safe, catalog initialization should
1982 * preferably be done once at startup
1983 */
1984void
1985xmlInitializeCatalog(void) {
1986 const char *catalogs;
1987
1988 if (xmlCatalogInitialized != 0)
1989 return;
1990
1991 if (getenv("XML_DEBUG_CATALOG"))
1992 xmlDebugCatalogs = 1;
1993 if ((xmlDefaultXMLCatalogList == NULL) && (xmlDefaultCatalog == NULL)) {
1994 catalogs = getenv("XML_CATALOG_FILES");
1995 if (catalogs == NULL)
1996 catalogs = XML_DEFAULT_CATALOG;
1997 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
1998 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
1999 }
2000
2001 xmlCatalogInitialized = 1;
2002}
2003
2004/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002005 * xmlLoadCatalog:
2006 * @filename: a file path
2007 *
Daniel Veillard81418e32001-05-22 15:08:55 +00002008 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002009 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002010 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002011 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00002012 *
2013 * Returns 0 in case of success -1 in case of error
2014 */
2015int
2016xmlLoadCatalog(const char *filename) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002017 int fd, len, ret, i;
Daniel Veillarda7374592001-05-10 14:17:55 +00002018 struct stat info;
2019 xmlChar *content;
2020
2021 if (filename == NULL)
2022 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002023
Daniel Veillarda7374592001-05-10 14:17:55 +00002024 if (xmlDefaultCatalog == NULL)
2025 xmlDefaultCatalog = xmlHashCreate(20);
2026 if (xmlDefaultCatalog == NULL)
2027 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002028
2029 /*
2030 * Need to be done after ...
2031 */
2032 if (!xmlCatalogInitialized)
2033 xmlInitializeCatalog();
2034
2035#ifdef HAVE_STAT
Daniel Veillarda7374592001-05-10 14:17:55 +00002036 if (stat(filename, &info) < 0)
2037 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002038#endif
Daniel Veillarda7374592001-05-10 14:17:55 +00002039
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002040 /*
2041 * Prevent loops
2042 */
2043 for (i = 0;i < catalNr;i++) {
Daniel Veillard81418e32001-05-22 15:08:55 +00002044 if (xmlStrEqual((const xmlChar *)catalTab[i],
2045 (const xmlChar *)filename)) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002046 xmlGenericError(xmlGenericErrorContext,
2047 "xmlLoadCatalog: %s seems to induce a loop\n",
2048 filename);
2049 return(-1);
2050 }
2051 }
2052 if (catalNr >= catalMax) {
2053 xmlGenericError(xmlGenericErrorContext,
2054 "xmlLoadCatalog: %s catalog list too deep\n",
2055 filename);
2056 return(-1);
2057 }
2058 catalTab[catalNr++] = filename;
2059
2060 if ((fd = open(filename, O_RDONLY)) < 0) {
2061 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00002062 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002063 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002064
2065 content = xmlMalloc(info.st_size + 10);
2066 if (content == NULL) {
2067 xmlGenericError(xmlGenericErrorContext,
2068 "realloc of %d byte failed\n", info.st_size + 10);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002069 catalNr--;
2070 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002071 }
2072 len = read(fd, content, info.st_size);
2073 if (len < 0) {
2074 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002075 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00002076 return(-1);
2077 }
2078 content[len] = 0;
2079 close(fd);
2080
Daniel Veillard344cee72001-08-20 00:08:40 +00002081 if ((content[0] == ' ') || (content[0] == '-') ||
2082 ((content[0] >= 'A') && (content[0] <= 'Z')) ||
2083 ((content[0] >= 'a') && (content[0] <= 'z')))
Daniel Veillardcda96922001-08-21 10:56:31 +00002084 ret = xmlParseSGMLCatalog(content, filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00002085 else {
2086 xmlCatalogEntryPtr catal, tmp;
2087 /* TODO: allow to switch the default preference */
2088 catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
2089 if (catal != NULL) {
2090 if (xmlDefaultXMLCatalogList == NULL)
2091 xmlDefaultXMLCatalogList = catal;
2092 else {
2093 tmp = xmlDefaultXMLCatalogList;
2094 while (tmp->next != NULL)
2095 tmp = tmp->next;
2096 tmp->next = catal;
2097 }
2098 ret = 0;
2099 } else
2100 ret = -1;
2101 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002102 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002103 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00002104 return(ret);
2105}
2106
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002107/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002108 * xmlLoadCatalogs:
2109 * @paths: a list of file path separated by ':' or spaces
2110 *
2111 * Load the catalogs and makes their definitions effective for the default
2112 * external entity loader.
2113 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002114 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002115 */
2116void
2117xmlLoadCatalogs(const char *pathss) {
2118 const char *cur;
2119 const char *paths;
2120 xmlChar *path;
2121
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002122 if (pathss == NULL)
2123 return;
2124
Daniel Veillard81418e32001-05-22 15:08:55 +00002125 cur = pathss;
2126 while ((cur != NULL) && (*cur != 0)) {
2127 while (IS_BLANK(*cur)) cur++;
2128 if (*cur != 0) {
2129 paths = cur;
2130 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2131 cur++;
2132 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2133 if (path != NULL) {
2134 xmlLoadCatalog((const char *) path);
2135 xmlFree(path);
2136 }
2137 }
2138 while (*cur == ':')
2139 cur++;
2140 }
2141}
2142
Daniel Veillarda7374592001-05-10 14:17:55 +00002143/**
2144 * xmlCatalogCleanup:
2145 *
2146 * Free up all the memory associated with catalogs
2147 */
2148void
2149xmlCatalogCleanup(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002150 if (xmlDebugCatalogs)
2151 xmlGenericError(xmlGenericErrorContext,
2152 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002153 if (xmlCatalogXMLFiles != NULL)
2154 xmlHashFree(xmlCatalogXMLFiles, NULL);
2155 xmlCatalogXMLFiles = NULL;
Daniel Veillardcda96922001-08-21 10:56:31 +00002156 if (xmlDefaultXMLCatalogList != NULL)
2157 xmlFreeCatalogEntryList(xmlDefaultXMLCatalogList);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002158 xmlDefaultXMLCatalogList = NULL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002159 xmlDefaultXMLCatalogList = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002160 if (xmlDefaultCatalog != NULL)
2161 xmlHashFree(xmlDefaultCatalog,
2162 (xmlHashDeallocator) xmlFreeCatalogEntry);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002163 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002164 xmlDebugCatalogs = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00002165 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002166 xmlCatalogInitialized = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00002167}
2168
2169/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002170 * xmlCatalogGetSystem:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002171 * @pubId: the public ID string
Daniel Veillarda7374592001-05-10 14:17:55 +00002172 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002173 * Try to lookup the system ID associated to a public ID
2174 * DEPRECATED, use xmlCatalogResolveSystem()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002175 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002176 * Returns the system ID if found or NULL otherwise.
Daniel Veillarda7374592001-05-10 14:17:55 +00002177 */
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002178const xmlChar *
2179xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002180 xmlChar *ret;
2181 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002182
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002183 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002184 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002185
2186 if (!xmlCatalogInitialized)
2187 xmlInitializeCatalog();
2188
2189 /*
2190 * Check first the XML catalogs
2191 */
2192 if (xmlDefaultXMLCatalogList != NULL) {
2193 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
2194 if (ret != NULL) {
2195 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
2196 result[sizeof(result) - 1] = 0;
2197 return(result);
2198 }
2199 }
2200
2201 if (xmlDefaultCatalog != NULL)
2202 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID));
2203 return(NULL);
2204}
2205
2206/**
2207 * xmlCatalogResolveSystem:
2208 * @sysId: the public ID string
2209 *
2210 * Try to lookup the catalog resource for a system ID
2211 *
2212 * Returns the system ID if found or NULL otherwise, the value returned
2213 * must be freed by the caller.
2214 */
2215xmlChar *
2216xmlCatalogResolveSystem(const xmlChar *sysID) {
2217 xmlCatalogEntryPtr catal;
2218 xmlChar *ret;
2219 const xmlChar *sgml;
2220
2221 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002222 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002223
2224 if (!xmlCatalogInitialized)
2225 xmlInitializeCatalog();
2226
2227 /*
2228 * Check first the XML catalogs
2229 */
2230 catal = xmlDefaultXMLCatalogList;
2231 if (catal != NULL) {
2232 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
2233 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2234 return(ret);
2235 }
2236
2237 if (xmlDefaultCatalog != NULL) {
2238 sgml = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
2239 if (sgml != NULL)
2240 return(xmlStrdup(sgml));
2241 }
Daniel Veillard344cee72001-08-20 00:08:40 +00002242 return(NULL);
2243}
2244
2245/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002246 * xmlCatalogGetPublic:
2247 * @pubId: the public ID string
2248 *
2249 * Try to lookup the system ID associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002250 * DEPRECATED, use xmlCatalogResolvePublic()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002251 *
2252 * Returns the system ID if found or NULL otherwise.
2253 */
2254const xmlChar *
2255xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002256 xmlChar *ret;
2257 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002258
Daniel Veillard344cee72001-08-20 00:08:40 +00002259 if (pubID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002260 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00002261
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002262 if (!xmlCatalogInitialized)
2263 xmlInitializeCatalog();
2264
2265 /*
2266 * Check first the XML catalogs
2267 */
2268 if (xmlDefaultXMLCatalogList != NULL) {
2269 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2270 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
2271 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
2272 result[sizeof(result) - 1] = 0;
2273 return(result);
2274 }
2275 }
2276
2277 if (xmlDefaultCatalog != NULL)
2278 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
2279 return(NULL);
2280}
2281
2282/**
2283 * xmlCatalogResolvePublic:
2284 * @pubId: the public ID string
2285 *
2286 * Try to lookup the system ID associated to a public ID
2287 *
2288 * Returns the system ID if found or NULL otherwise, the value returned
2289 * must be freed by the caller.
2290 */
2291xmlChar *
2292xmlCatalogResolvePublic(const xmlChar *pubID) {
2293 xmlCatalogEntryPtr catal;
2294 xmlChar *ret;
2295 const xmlChar *sgml;
2296
2297 if (pubID == NULL)
2298 return(NULL);
2299
2300 if (!xmlCatalogInitialized)
2301 xmlInitializeCatalog();
2302
Daniel Veillard344cee72001-08-20 00:08:40 +00002303 /*
2304 * Check first the XML catalogs
2305 */
2306 catal = xmlDefaultXMLCatalogList;
2307 if (catal != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002308 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2309 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
Daniel Veillard344cee72001-08-20 00:08:40 +00002310 return(ret);
2311 }
2312
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002313 if (xmlDefaultCatalog != NULL) {
2314 sgml = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
2315 if (sgml != NULL)
2316 return(xmlStrdup(sgml));
2317 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002318 return(NULL);
2319}
Daniel Veillard344cee72001-08-20 00:08:40 +00002320
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002321/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002322 * xmlCatalogResolve:
2323 * @pubId: the public ID string
2324 * @sysId: the system ID string
2325 *
2326 * Do a complete resolution lookup of an External Identifier
2327 *
2328 * Returns the URI of the resource or NULL if not found, it must be freed
2329 * by the caller.
2330 */
2331xmlChar *
2332xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002333 if ((pubID == NULL) && (sysID == NULL))
2334 return(NULL);
2335
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002336 if (!xmlCatalogInitialized)
2337 xmlInitializeCatalog();
2338
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002339 if (xmlDebugCatalogs) {
2340 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002341 xmlGenericError(xmlGenericErrorContext,
2342 "Resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002343 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002344 xmlGenericError(xmlGenericErrorContext,
2345 "Resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002346 }
2347 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00002348
Daniel Veillardcda96922001-08-21 10:56:31 +00002349 if (xmlDefaultXMLCatalogList != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002350 xmlChar *ret;
2351 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, sysID);
2352 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2353 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002354 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002355 const xmlChar *ret;
2356
2357 ret = xmlCatalogSGMLResolve(pubID, sysID);
2358 if (ret != NULL)
2359 return(xmlStrdup(ret));
Daniel Veillardcda96922001-08-21 10:56:31 +00002360 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002361 return(NULL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002362}
2363
2364/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002365 * xmlCatalogResolveURI:
2366 * @pubId: the URI
2367 *
2368 * Do a complete resolution lookup of an URI
2369 *
2370 * Returns the URI of the resource or NULL if not found, it must be freed
2371 * by the caller.
2372 */
2373xmlChar *
2374xmlCatalogResolveURI(const xmlChar *URI) {
2375 if (!xmlCatalogInitialized)
2376 xmlInitializeCatalog();
2377
Daniel Veillard6990bf32001-08-23 21:17:48 +00002378 if (URI == NULL)
2379 return(NULL);
2380
2381 if (xmlDebugCatalogs)
2382 xmlGenericError(xmlGenericErrorContext,
2383 "Resolve URI %s\n", URI);
2384
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002385 if (xmlDefaultXMLCatalogList != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002386 xmlChar *ret;
2387
2388 ret = xmlCatalogListXMLResolveURI(xmlDefaultXMLCatalogList, URI);
2389 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2390 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002391 } else {
2392 const xmlChar *ret;
2393
2394 ret = xmlCatalogSGMLResolve(NULL, URI);
2395 if (ret != NULL)
2396 return(xmlStrdup(ret));
2397 }
2398 return(NULL);
2399}
2400
2401/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002402 * xmlCatalogDump:
2403 * @out: the file.
2404 *
2405 * Free up all the memory associated with catalogs
2406 */
2407void
2408xmlCatalogDump(FILE *out) {
2409 if (out == NULL)
2410 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00002411
2412 if (xmlDefaultXMLCatalogList != NULL) {
2413 xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList);
2414 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002415 xmlHashScan(xmlDefaultCatalog,
2416 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00002417 }
2418}
2419
2420/**
2421 * xmlCatalogAdd:
2422 * @type: the type of record to add to the catalog
2423 * @orig: the system, public or prefix to match
2424 * @replace: the replacement value for the match
2425 *
2426 * Add an entry in the catalog, it may overwrite existing but
2427 * different entries.
2428 *
2429 * Returns 0 if successful, -1 otherwise
2430 */
2431int
2432xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
2433 int res = -1;
2434
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00002435 if ((xmlDefaultXMLCatalogList == NULL) &&
2436 (xmlStrEqual(type, BAD_CAST "catalog"))) {
2437 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2438 orig, xmlCatalogDefaultPrefer);
2439 return(0);
2440 }
2441
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002442 if (!xmlCatalogInitialized)
2443 xmlInitializeCatalog();
2444
Daniel Veillard344cee72001-08-20 00:08:40 +00002445 if (xmlDefaultXMLCatalogList != NULL) {
2446 res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
2447 } else if (xmlDefaultCatalog != NULL) {
2448 xmlCatalogEntryType typ;
2449
Daniel Veillardcda96922001-08-21 10:56:31 +00002450 typ = xmlGetSGMLCatalogEntryType(type);
Daniel Veillard344cee72001-08-20 00:08:40 +00002451 if (type != XML_CATA_NONE) {
2452 xmlCatalogEntryPtr entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002453 entry = xmlNewCatalogEntry(typ, orig, replace,
2454 XML_CATA_PREFER_NONE);
Daniel Veillard344cee72001-08-20 00:08:40 +00002455 res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
2456 }
2457 }
2458 return(res);
2459}
2460
2461/**
2462 * xmlCatalogRemove:
2463 * @value: the value to remove
2464 *
2465 * Remove an entry from the catalog
2466 *
2467 * Returns 0 if successful, -1 otherwise
2468 */
2469int
2470xmlCatalogRemove(const xmlChar *value) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002471 int res = -1;
2472
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002473 if (!xmlCatalogInitialized)
2474 xmlInitializeCatalog();
2475
Daniel Veillardcda96922001-08-21 10:56:31 +00002476 if (xmlDefaultXMLCatalogList != NULL) {
2477 res = xmlDelXMLCatalog(xmlDefaultXMLCatalogList, value);
2478 } else if (xmlDefaultCatalog != NULL) {
2479 TODO
2480 }
2481 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00002482}
2483
2484/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002485 * xmlCatalogConvert:
2486 *
2487 * Convert all the SGML catalog entries as XML ones
2488 *
2489 * Returns the number of entries converted if successful, -1 otherwise
2490 */
2491int
2492xmlCatalogConvert(void) {
2493 int res = -1;
2494
2495 if (!xmlCatalogInitialized)
2496 xmlInitializeCatalog();
2497
2498 if (xmlDebugCatalogs) {
2499 xmlGenericError(xmlGenericErrorContext,
2500 "Converting SGML catalog to XML\n");
2501 }
2502
2503 if (xmlDefaultXMLCatalogList == NULL) {
2504 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
2505 NULL, BAD_CAST "NewCatalog.xml",
2506 xmlCatalogDefaultPrefer);
2507 }
2508 if (xmlDefaultCatalog != NULL) {
2509 res = 0;
2510
2511 xmlHashScan(xmlDefaultCatalog,
2512 (xmlHashScanner) xmlCatalogConvertEntry, &res);
2513 }
2514 return(res);
2515}
2516
2517/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002518 * xmlCatalogGetDefaults:
2519 *
2520 * Used to get the user preference w.r.t. to what catalogs should
2521 * be accepted
2522 *
2523 * Returns the current xmlCatalogAllow value
2524 */
2525xmlCatalogAllow
2526xmlCatalogGetDefaults(void) {
2527 return(xmlCatalogDefaultAllow);
2528}
2529
2530/**
2531 * xmlCatalogSetDefaults:
2532 *
2533 * Used to set the user preference w.r.t. to what catalogs should
2534 * be accepted
2535 */
2536void
2537xmlCatalogSetDefaults(xmlCatalogAllow allow) {
2538 if (!xmlCatalogInitialized)
2539 xmlInitializeCatalog();
2540 if (xmlDebugCatalogs) {
2541 switch (allow) {
2542 case XML_CATA_ALLOW_NONE:
2543 xmlGenericError(xmlGenericErrorContext,
2544 "Disabling catalog usage\n");
2545 break;
2546 case XML_CATA_ALLOW_GLOBAL:
2547 xmlGenericError(xmlGenericErrorContext,
2548 "Allowing only global catalogs\n");
2549 break;
2550 case XML_CATA_ALLOW_DOCUMENT:
2551 xmlGenericError(xmlGenericErrorContext,
2552 "Allowing only catalogs from the document\n");
2553 break;
2554 case XML_CATA_ALLOW_ALL:
2555 xmlGenericError(xmlGenericErrorContext,
2556 "Allowing all catalogs\n");
2557 break;
2558 }
2559 }
2560 xmlCatalogDefaultAllow = allow;
2561}
2562
2563/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002564 * xmlCatalogSetDefaultPrefer:
2565 * @prefer: the default preference for delegation
2566 *
2567 * Allows to set the preference between public and system for deletion
2568 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002569 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002570 *
2571 * Returns the previous value of the default preference for delegation
2572 */
2573xmlCatalogPrefer
2574xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
2575 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
2576
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002577 if (!xmlCatalogInitialized)
2578 xmlInitializeCatalog();
2579 if (prefer == XML_CATA_PREFER_NONE)
2580 return(ret);
2581
2582 if (xmlDebugCatalogs) {
2583 switch (prefer) {
2584 case XML_CATA_PREFER_PUBLIC:
2585 xmlGenericError(xmlGenericErrorContext,
2586 "Setting catalog preference to PUBLIC\n");
2587 break;
2588 case XML_CATA_PREFER_SYSTEM:
2589 xmlGenericError(xmlGenericErrorContext,
2590 "Setting catalog preference to SYSTEM\n");
2591 break;
2592 case XML_CATA_PREFER_NONE:
2593 break;
2594 }
2595 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002596 xmlCatalogDefaultPrefer = prefer;
2597 return(ret);
2598}
2599
2600/**
Daniel Veillard344cee72001-08-20 00:08:40 +00002601 * xmlCatalogSetDebug:
2602 * @level: the debug level of catalogs required
2603 *
2604 * Used to set the debug level for catalog operation, 0 disable
2605 * debugging, 1 enable it
2606 *
2607 * Returns the previous value of the catalog debugging level
2608 */
2609int
2610xmlCatalogSetDebug(int level) {
2611 int ret = xmlDebugCatalogs;
2612
2613 if (level <= 0)
2614 xmlDebugCatalogs = 0;
2615 else
2616 xmlDebugCatalogs = level;
2617 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002618}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002619
2620/**
2621 * xmlCatalogFreeLocal:
2622 * @catalogs: a document's list of catalogs
2623 *
2624 * Free up the memory associated to the catalog list
2625 */
2626void
2627xmlCatalogFreeLocal(void *catalogs) {
2628 xmlCatalogEntryPtr catal;
2629
2630 catal = (xmlCatalogEntryPtr) catalogs;
2631 if (catal != NULL)
2632 xmlFreeCatalogEntryList(catal);
2633}
2634
2635
2636/**
2637 * xmlCatalogAddLocal:
2638 * @catalogs: a document's list of catalogs
2639 * @URL: the URL to a new local catalog
2640 *
2641 * Add the new entry to the catalog list
2642 *
2643 * Returns the updated list
2644 */
2645void *
2646xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
2647 xmlCatalogEntryPtr catal, add;
2648
2649 if (!xmlCatalogInitialized)
2650 xmlInitializeCatalog();
2651 if (URL == NULL)
2652 return(catalogs);
2653
2654 if (xmlDebugCatalogs)
2655 xmlGenericError(xmlGenericErrorContext,
2656 "Adding document catalog %s\n", URL);
2657
2658 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
2659 xmlCatalogDefaultPrefer);
2660 if (add == NULL)
2661 return(catalogs);
2662
2663 catal = (xmlCatalogEntryPtr) catalogs;
2664 if (catal == NULL)
2665 return((void *) add);
2666
2667 while (catal->next != NULL)
2668 catal = catal->next;
2669 catal->next = add;
2670 return(catalogs);
2671}
2672
2673/**
2674 * xmlCatalogLocalResolve:
2675 * @catalogs: a document's list of catalogs
2676 * @pubId: the public ID string
2677 * @sysId: the system ID string
2678 *
2679 * Do a complete resolution lookup of an External Identifier using a
2680 * document's private catalog list
2681 *
2682 * Returns the URI of the resource or NULL if not found, it must be freed
2683 * by the caller.
2684 */
2685xmlChar *
2686xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
2687 const xmlChar *sysID) {
2688 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002689 xmlChar *ret;
2690
2691 if ((pubID == NULL) && (sysID == NULL))
2692 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002693
2694 if (!xmlCatalogInitialized)
2695 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00002696
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002697 if (xmlDebugCatalogs) {
2698 if (pubID != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002699 xmlGenericError(xmlGenericErrorContext,
2700 "Local resolve: pubID %s\n", pubID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002701 } else {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002702 xmlGenericError(xmlGenericErrorContext,
2703 "Local resolve: sysID %s\n", sysID);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00002704 }
2705 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00002706
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002707 catal = (xmlCatalogEntryPtr) catalogs;
2708 if (catal == NULL)
2709 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002710 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
2711 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2712 return(ret);
2713 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002714}
2715
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002716/**
2717 * xmlCatalogLocalResolveURI:
2718 * @catalogs: a document's list of catalogs
2719 * @pubId: the URI
2720 *
2721 * Do a complete resolution lookup of an URI using a
2722 * document's private catalog list
2723 *
2724 * Returns the URI of the resource or NULL if not found, it must be freed
2725 * by the caller.
2726 */
2727xmlChar *
2728xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
2729 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002730 xmlChar *ret;
2731
2732 if (URI == NULL)
2733 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002734
2735 if (!xmlCatalogInitialized)
2736 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00002737
2738 if (xmlDebugCatalogs)
2739 xmlGenericError(xmlGenericErrorContext,
2740 "Resolve URI %s\n", URI);
2741
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002742 catal = (xmlCatalogEntryPtr) catalogs;
2743 if (catal == NULL)
2744 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002745 ret = xmlCatalogListXMLResolveURI(catal, URI);
2746 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2747 return(ret);
2748 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002749}
2750
Daniel Veillarda7374592001-05-10 14:17:55 +00002751#endif /* LIBXML_CATALOG_ENABLED */