blob: bd120aea47a123d9e9b895de0a3004c027a4a031 [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)
52#define XML_DEFAULT_CATALOG "/etc/xml/catalog"
Daniel Veillard344cee72001-08-20 00:08:40 +000053
Daniel Veillarda7374592001-05-10 14:17:55 +000054/************************************************************************
55 * *
56 * Types, all private *
57 * *
58 ************************************************************************/
59
60typedef enum {
61 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +000062 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +000063 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +000064 XML_CATA_NEXT_CATALOG,
65 XML_CATA_PUBLIC,
66 XML_CATA_SYSTEM,
67 XML_CATA_REWRITE_SYSTEM,
68 XML_CATA_DELEGATE_PUBLIC,
69 XML_CATA_DELEGATE_SYSTEM,
70 XML_CATA_URI,
71 XML_CATA_REWRITE_URI,
72 XML_CATA_DELEGATE_URI,
73 SGML_CATA_SYSTEM,
74 SGML_CATA_PUBLIC,
75 SGML_CATA_ENTITY,
76 SGML_CATA_PENTITY,
77 SGML_CATA_DOCTYPE,
78 SGML_CATA_LINKTYPE,
79 SGML_CATA_NOTATION,
80 SGML_CATA_DELEGATE,
81 SGML_CATA_BASE,
82 SGML_CATA_CATALOG,
83 SGML_CATA_DOCUMENT,
84 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +000085} xmlCatalogEntryType;
86
87typedef struct _xmlCatalogEntry xmlCatalogEntry;
88typedef xmlCatalogEntry *xmlCatalogEntryPtr;
89struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +000090 struct _xmlCatalogEntry *next;
91 struct _xmlCatalogEntry *parent;
92 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +000093 xmlCatalogEntryType type;
94 xmlChar *name;
95 xmlChar *value;
Daniel Veillarde2940dd2001-08-22 00:06:49 +000096 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +000097 int dealloc;
Daniel Veillarda7374592001-05-10 14:17:55 +000098};
99
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000100static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000101static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +0000102static xmlHashTablePtr xmlDefaultCatalog;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000103static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard344cee72001-08-20 00:08:40 +0000104static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000105static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000106
Daniel Veillarda7374592001-05-10 14:17:55 +0000107
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000108/* Catalog stack */
Daniel Veillard81418e32001-05-22 15:08:55 +0000109static const char * catalTab[10]; /* stack of catals */
110static int catalNr = 0; /* Number of current catal streams */
111static int catalMax = 10; /* Max number of catal streams */
Daniel Veillardaf86c7f2001-05-21 14:11:26 +0000112
Daniel Veillard344cee72001-08-20 00:08:40 +0000113static int xmlDebugCatalogs = 0; /* used for debugging */
114
Daniel Veillarda7374592001-05-10 14:17:55 +0000115/************************************************************************
116 * *
117 * alloc or dealloc *
118 * *
119 ************************************************************************/
120
121static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000122xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000123 const xmlChar *value, xmlCatalogPrefer prefer) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000124 xmlCatalogEntryPtr ret;
125
126 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
127 if (ret == NULL) {
128 xmlGenericError(xmlGenericErrorContext,
129 "malloc of %d byte failed\n", sizeof(xmlCatalogEntry));
130 return(NULL);
131 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000132 ret->next = NULL;
133 ret->parent = NULL;
134 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000135 ret->type = type;
Daniel Veillard344cee72001-08-20 00:08:40 +0000136 if (name != NULL)
137 ret->name = xmlStrdup(name);
138 else
139 ret->name = NULL;
140 if (value != NULL)
141 ret->value = xmlStrdup(value);
142 else
143 ret->value = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000144 ret->prefer = prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000145 ret->dealloc = 1;
Daniel Veillarda7374592001-05-10 14:17:55 +0000146 return(ret);
147}
148
149static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000150xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
151
152static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000153xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
154 if (ret == NULL)
155 return;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000156 if ((ret->children != NULL) && (ret->dealloc == 1))
Daniel Veillard344cee72001-08-20 00:08:40 +0000157 xmlFreeCatalogEntryList(ret->children);
Daniel Veillarda7374592001-05-10 14:17:55 +0000158 if (ret->name != NULL)
159 xmlFree(ret->name);
160 if (ret->value != NULL)
161 xmlFree(ret->value);
162 xmlFree(ret);
163}
164
Daniel Veillard344cee72001-08-20 00:08:40 +0000165static void
166xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
167 xmlCatalogEntryPtr next;
168
169 while (ret != NULL) {
170 next = ret->next;
171 xmlFreeCatalogEntry(ret);
172 ret = next;
173 }
174}
175
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000176/**
177 * xmlCatalogDumpEntry:
178 * @entry: the
179 * @out: the file.
180 *
181 * Free up all the memory associated with catalogs
182 */
183static void
184xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
185 if ((entry == NULL) || (out == NULL))
186 return;
187 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000188 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000189 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000190 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000191 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000192 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000193 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000194 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000195 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000196 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000197 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000198 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000199 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000200 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000201 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000202 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000203 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000204 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000205 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000206 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000207 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000208 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000209 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000210 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000211 fprintf(out, "SGMLDECL "); break;
212 default:
213 return;
214 }
215 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000216 case SGML_CATA_ENTITY:
217 case SGML_CATA_PENTITY:
218 case SGML_CATA_DOCTYPE:
219 case SGML_CATA_LINKTYPE:
220 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000221 fprintf(out, "%s", entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000222 case SGML_CATA_PUBLIC:
223 case SGML_CATA_SYSTEM:
224 case SGML_CATA_SGMLDECL:
225 case SGML_CATA_DOCUMENT:
226 case SGML_CATA_CATALOG:
227 case SGML_CATA_BASE:
228 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000229 fprintf(out, "\"%s\"", entry->name); break;
230 default:
231 break;
232 }
233 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000234 case SGML_CATA_ENTITY:
235 case SGML_CATA_PENTITY:
236 case SGML_CATA_DOCTYPE:
237 case SGML_CATA_LINKTYPE:
238 case SGML_CATA_NOTATION:
239 case SGML_CATA_PUBLIC:
240 case SGML_CATA_SYSTEM:
241 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000242 fprintf(out, " \"%s\"", entry->value); break;
243 default:
244 break;
245 }
246 fprintf(out, "\n");
247}
248
Daniel Veillarda7374592001-05-10 14:17:55 +0000249/************************************************************************
250 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000251 * Helper function *
252 * *
253 ************************************************************************/
254
255/**
256 * xmlCatalogUnWrapURN:
257 * @urn: an "urn:publicid:" to unwrapp
258 *
259 * Expand the URN into the equivalent Public Identifier
260 *
261 * Returns the new identifier or NULL, the string must be deallocated
262 * by the caller.
263 */
264static xmlChar *
265xmlCatalogUnWrapURN(const xmlChar *urn) {
266 xmlChar result[2000];
267 unsigned int i = 0;
268
269 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
270 return(NULL);
271 urn += sizeof(XML_URN_PUBID) - 1;
272
273 while (*urn != 0) {
274 if (i > sizeof(result) - 3)
275 break;
276 if (*urn == '+') {
277 result[i++] = ' ';
278 urn++;
279 } else if (*urn == ':') {
280 result[i++] = '/';
281 result[i++] = '/';
282 urn++;
283 } else if (*urn == ';') {
284 result[i++] = ':';
285 result[i++] = ':';
286 urn++;
287 } else if (*urn == '%') {
288 if ((urn[1] == '2') && (urn[1] == 'B'))
289 result[i++] = '+';
290 else if ((urn[1] == '3') && (urn[1] == 'A'))
291 result[i++] = ':';
292 else if ((urn[1] == '2') && (urn[1] == 'F'))
293 result[i++] = '/';
294 else if ((urn[1] == '3') && (urn[1] == 'B'))
295 result[i++] = ';';
296 else if ((urn[1] == '2') && (urn[1] == '7'))
297 result[i++] = '\'';
298 else if ((urn[1] == '3') && (urn[1] == 'F'))
299 result[i++] = '?';
300 else if ((urn[1] == '2') && (urn[1] == '3'))
301 result[i++] = '#';
302 else if ((urn[1] == '2') && (urn[1] == '5'))
303 result[i++] = '%';
304 else {
305 result[i++] = *urn;
306 urn++;
307 continue;
308 }
309 urn += 3;
310 } else {
311 result[i++] = *urn;
312 urn++;
313 }
314 }
315 result[i] = 0;
316
317 return(xmlStrdup(result));
318}
319
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000320/**
321 * xmlParseCatalogFile:
322 * @filename: the filename
323 *
324 * parse an XML file and build a tree. It's like xmlParseFile()
325 * except it bypass all catalog lookups.
326 *
327 * Returns the resulting document tree or NULL in case of error
328 */
329
330xmlDocPtr
331xmlParseCatalogFile(const char *filename) {
332 xmlDocPtr ret;
333 xmlParserCtxtPtr ctxt;
334 char *directory = NULL;
335 xmlParserInputPtr inputStream;
336 xmlParserInputBufferPtr buf;
337
338 ctxt = xmlNewParserCtxt();
339 if (ctxt == NULL) {
340 if (xmlDefaultSAXHandler.error != NULL) {
341 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
342 }
343 return(NULL);
344 }
345
346 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
347 if (buf == NULL) {
348 xmlFreeParserCtxt(ctxt);
349 return(NULL);
350 }
351
352 inputStream = xmlNewInputStream(ctxt);
353 if (inputStream == NULL) {
354 xmlFreeParserCtxt(ctxt);
355 return(NULL);
356 }
357
358 inputStream->filename = xmlMemStrdup(filename);
359 inputStream->buf = buf;
360 inputStream->base = inputStream->buf->buffer->content;
361 inputStream->cur = inputStream->buf->buffer->content;
362 inputStream->end =
363 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
364
365 inputPush(ctxt, inputStream);
366 if ((ctxt->directory == NULL) && (directory == NULL))
367 directory = xmlParserGetDirectory(filename);
368 if ((ctxt->directory == NULL) && (directory != NULL))
369 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000370 ctxt->valid = 0;
371 ctxt->validate = 0;
372 ctxt->loadsubset = 0;
373 ctxt->pedantic = 0;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000374
375 xmlParseDocument(ctxt);
376
377 if (ctxt->wellFormed)
378 ret = ctxt->myDoc;
379 else {
380 ret = NULL;
381 xmlFreeDoc(ctxt->myDoc);
382 ctxt->myDoc = NULL;
383 }
384 xmlFreeParserCtxt(ctxt);
385
386 return(ret);
387}
388
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000389/************************************************************************
390 * *
Daniel Veillard344cee72001-08-20 00:08:40 +0000391 * The XML Catalog parser *
392 * *
393 ************************************************************************/
394
395static xmlCatalogEntryPtr
396xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000397static xmlCatalogEntryPtr
398xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
399 const char *file);
400static void
401xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
402 xmlCatalogEntryPtr parent);
Daniel Veillardcda96922001-08-21 10:56:31 +0000403static xmlChar *
404xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
405 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +0000406static xmlChar *
407xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
408
Daniel Veillard344cee72001-08-20 00:08:40 +0000409
410static xmlCatalogEntryType
411xmlGetXMLCatalogEntryType(const xmlChar *name) {
412 xmlCatalogEntryType type = XML_CATA_NONE;
413 if (xmlStrEqual(name, (const xmlChar *) "system"))
414 type = XML_CATA_SYSTEM;
415 else if (xmlStrEqual(name, (const xmlChar *) "public"))
416 type = XML_CATA_PUBLIC;
417 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
418 type = XML_CATA_REWRITE_SYSTEM;
419 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
420 type = XML_CATA_DELEGATE_PUBLIC;
421 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
422 type = XML_CATA_DELEGATE_SYSTEM;
423 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
424 type = XML_CATA_URI;
425 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
426 type = XML_CATA_REWRITE_URI;
427 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
428 type = XML_CATA_DELEGATE_URI;
429 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
430 type = XML_CATA_NEXT_CATALOG;
431 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
432 type = XML_CATA_CATALOG;
433 return(type);
434}
435
436static xmlCatalogEntryPtr
437xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
438 const xmlChar *name, const xmlChar *attrName,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000439 const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000440 int ok = 1;
441 xmlChar *uriValue;
442 xmlChar *nameValue = NULL;
443 xmlChar *base = NULL;
444 xmlChar *URL = NULL;
445 xmlCatalogEntryPtr ret = NULL;
446
447 if (attrName != NULL) {
448 nameValue = xmlGetProp(cur, attrName);
449 if (nameValue == NULL) {
450 xmlGenericError(xmlGenericErrorContext,
451 "%s entry lacks '%s'\n", name, attrName);
452 ok = 0;
453 }
454 }
455 uriValue = xmlGetProp(cur, uriAttrName);
456 if (uriValue == NULL) {
457 xmlGenericError(xmlGenericErrorContext,
458 "%s entry lacks '%s'\n", name, uriAttrName);
459 ok = 0;
460 }
461 if (!ok) {
462 if (nameValue != NULL)
463 xmlFree(nameValue);
464 if (uriValue != NULL)
465 xmlFree(uriValue);
466 return(NULL);
467 }
468
469 base = xmlNodeGetBase(cur->doc, cur);
470 URL = xmlBuildURI(uriValue, base);
471 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000472 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000473 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000474 xmlGenericError(xmlGenericErrorContext,
475 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000476 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000477 xmlGenericError(xmlGenericErrorContext,
478 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000479 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000480 ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000481 } else {
482 xmlGenericError(xmlGenericErrorContext,
483 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
484 }
485 if (nameValue != NULL)
486 xmlFree(nameValue);
487 if (uriValue != NULL)
488 xmlFree(uriValue);
489 if (base != NULL)
490 xmlFree(base);
491 if (URL != NULL)
492 xmlFree(URL);
493 return(ret);
494}
495
496static void
497xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
498 xmlCatalogEntryPtr parent)
499{
500 xmlChar *uri = NULL;
501 xmlChar *URL = NULL;
502 xmlChar *base = NULL;
503 xmlCatalogEntryPtr entry = NULL;
504
505 if (cur == NULL)
506 return;
507 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
508 xmlChar *prop;
509
510 prop = xmlGetProp(cur, BAD_CAST "prefer");
511 if (prop != NULL) {
512 if (xmlStrEqual(prop, BAD_CAST "system")) {
513 prefer = XML_CATA_PREFER_SYSTEM;
514 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
515 prefer = XML_CATA_PREFER_PUBLIC;
516 } else {
517 xmlGenericError(xmlGenericErrorContext,
518 "Invalid value for prefer: '%s'\n", prop);
519 }
520 xmlFree(prop);
521 }
522 /*
523 * Recurse to propagate prefer to the subtree
524 * (xml:base handling is automated)
525 */
526 xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
527 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
528 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000529 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000530 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
531 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000532 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000533 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
534 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
535 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000536 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000537 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
538 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
539 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000540 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000541 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
542 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
543 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000544 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000545 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
546 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
547 BAD_CAST "uri", BAD_CAST "name",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000548 BAD_CAST "uri", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000549 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
550 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
551 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000552 BAD_CAST "rewritePrefix", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000553 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
554 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
555 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000556 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000557 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
558 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
559 BAD_CAST "nextCatalog", NULL,
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000560 BAD_CAST "catalog", prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000561 }
562 if ((entry != NULL) && (parent != NULL)) {
563 entry->parent = parent;
564 if (parent->children == NULL)
565 parent->children = entry;
566 else {
567 xmlCatalogEntryPtr prev;
568
569 prev = parent->children;
570 while (prev->next != NULL)
571 prev = prev->next;
572 prev->next = entry;
573 }
574 }
575 if (base != NULL)
576 xmlFree(base);
577 if (uri != NULL)
578 xmlFree(uri);
579 if (URL != NULL)
580 xmlFree(URL);
581}
582
583static void
584xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
585 xmlCatalogEntryPtr parent) {
586 while (cur != NULL) {
587 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
588 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
589 xmlParseXMLCatalogNode(cur, prefer, parent);
590 }
591 cur = cur->next;
592 }
593 /* TODO: sort the list according to REWRITE lengths and prefer value */
594}
595
596static xmlCatalogEntryPtr
597xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer,
598 const char *file) {
599 xmlDocPtr doc;
600 xmlNodePtr cur;
601 xmlChar *prop;
602 xmlCatalogEntryPtr parent = NULL;
603
604 if ((value == NULL) || (file == NULL))
605 return(NULL);
606
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000607 if (xmlDebugCatalogs)
608 xmlGenericError(xmlGenericErrorContext,
609 "Parsing catalog %s's content\n", file);
610
Daniel Veillard344cee72001-08-20 00:08:40 +0000611 doc = xmlParseDoc((xmlChar *) value);
612 if (doc == NULL)
613 return(NULL);
614 doc->URL = xmlStrdup((const xmlChar *) file);
615
616 cur = xmlDocGetRootElement(doc);
617 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
618 (cur->ns != NULL) && (cur->ns->href != NULL) &&
619 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
620
Daniel Veillard344cee72001-08-20 00:08:40 +0000621 prop = xmlGetProp(cur, BAD_CAST "prefer");
622 if (prop != NULL) {
623 if (xmlStrEqual(prop, BAD_CAST "system")) {
624 prefer = XML_CATA_PREFER_SYSTEM;
625 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
626 prefer = XML_CATA_PREFER_PUBLIC;
627 } else {
628 xmlGenericError(xmlGenericErrorContext,
629 "Invalid value for prefer: '%s'\n",
630 prop);
631 }
632 xmlFree(prop);
633 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000634 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
635 (const xmlChar *)file, prefer);
636 if (parent == NULL) {
637 xmlFreeDoc(doc);
638 return(NULL);
639 }
640
Daniel Veillard344cee72001-08-20 00:08:40 +0000641 cur = cur->children;
642 xmlParseXMLCatalogNodeList(cur, prefer, parent);
643 } else {
644 xmlGenericError(xmlGenericErrorContext,
645 "File %s is not an XML Catalog\n", file);
646 xmlFreeDoc(doc);
647 return(NULL);
648 }
649 xmlFreeDoc(doc);
650 return(parent);
651}
652
653static xmlCatalogEntryPtr
654xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
655 xmlDocPtr doc;
656 xmlNodePtr cur;
657 xmlChar *prop;
658 xmlCatalogEntryPtr parent = NULL;
659
660 if (filename == NULL)
661 return(NULL);
662
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000663 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000664 if (doc == NULL) {
665 if (xmlDebugCatalogs)
666 xmlGenericError(xmlGenericErrorContext,
667 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000668 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000669 }
670
671 if (xmlDebugCatalogs)
672 xmlGenericError(xmlGenericErrorContext,
673 "Parsing catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +0000674
675 cur = xmlDocGetRootElement(doc);
676 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
677 (cur->ns != NULL) && (cur->ns->href != NULL) &&
678 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
679
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000680 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
681 (const xmlChar *)filename, prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000682 if (parent == NULL) {
683 xmlFreeDoc(doc);
684 return(NULL);
685 }
686
687 prop = xmlGetProp(cur, BAD_CAST "prefer");
688 if (prop != NULL) {
689 if (xmlStrEqual(prop, BAD_CAST "system")) {
690 prefer = XML_CATA_PREFER_SYSTEM;
691 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
692 prefer = XML_CATA_PREFER_PUBLIC;
693 } else {
694 xmlGenericError(xmlGenericErrorContext,
695 "Invalid value for prefer: '%s'\n",
696 prop);
697 }
698 xmlFree(prop);
699 }
700 cur = cur->children;
701 xmlParseXMLCatalogNodeList(cur, prefer, parent);
702 } else {
703 xmlGenericError(xmlGenericErrorContext,
704 "File %s is not an XML Catalog\n", filename);
705 xmlFreeDoc(doc);
706 return(NULL);
707 }
708 xmlFreeDoc(doc);
709 return(parent);
710}
711
Daniel Veillardcda96922001-08-21 10:56:31 +0000712/**
713 * xmlFetchXMLCatalogFile:
714 * @catal: an existing but incomplete catalog entry
715 *
716 * Fetch and parse the subcatalog referenced by an entry
717 * It tries to be thread safe but by lack of an atomic test and
718 * set there is a risk of loosing memory.
719 *
720 * Returns 0 in case of success, -1 otherwise
721 */
722static int
723xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard6990bf32001-08-23 21:17:48 +0000724 xmlCatalogEntryPtr children = NULL, doc;
Daniel Veillardcda96922001-08-21 10:56:31 +0000725
726 if (catal == NULL)
727 return(-1);
728 if (catal->value == NULL)
729 return(-1);
730 if (catal->children != NULL)
731 return(-1);
732
Daniel Veillard6990bf32001-08-23 21:17:48 +0000733 if (xmlCatalogXMLFiles != NULL)
734 children = (xmlCatalogEntryPtr)
735 xmlHashLookup(xmlCatalogXMLFiles, catal->value);
736 if (children != NULL) {
737 catal->children = children;
738 catal->dealloc = 0;
739 return(0);
740 }
741
Daniel Veillardcda96922001-08-21 10:56:31 +0000742 /*
743 * Fetch and parse
744 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000745 doc = xmlParseXMLCatalogFile(catal->prefer, catal->value);
746 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000747 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillardcda96922001-08-21 10:56:31 +0000748 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000749 }
Daniel Veillard6990bf32001-08-23 21:17:48 +0000750 if ((catal->type == XML_CATA_CATALOG) &&
751 (doc->type == XML_CATA_CATALOG)) {
752 children = doc->children;
753 doc->children = NULL;
754 xmlFreeCatalogEntryList(doc);
755 } else {
756 children = doc;
757 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000758
759 /*
760 * Where a real test and set would be needed !
761 */
762 if (catal->children == NULL) {
763 catal->children = children;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000764 catal->dealloc = 1;
765 if (xmlCatalogXMLFiles == NULL)
766 xmlCatalogXMLFiles = xmlHashCreate(10);
767 if (xmlCatalogXMLFiles != NULL) {
768 if (children != NULL)
769 xmlHashAddEntry(xmlCatalogXMLFiles, catal->value, children);
770 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000771 } else {
772 /*
773 * Another thread filled it before us
774 */
775 xmlFreeCatalogEntryList(children);
776 }
777 return(0);
778}
779
Daniel Veillard344cee72001-08-20 00:08:40 +0000780static int
781xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
782 int ret;
783 xmlDocPtr doc;
784 xmlNsPtr ns;
785 xmlDtdPtr dtd;
786 xmlNodePtr node, catalog;
787 xmlOutputBufferPtr buf;
788 xmlCatalogEntryPtr cur;
789
790 /*
791 * Rebuild a catalog
792 */
793 doc = xmlNewDoc(NULL);
794 if (doc == NULL)
795 return(-1);
796 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
797 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
798BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
799
800 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
801
802 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
803 if (ns == NULL) {
804 xmlFreeDoc(doc);
805 return(-1);
806 }
807 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
808 if (catalog == NULL) {
809 xmlFreeNs(ns);
810 xmlFreeDoc(doc);
811 return(-1);
812 }
813 catalog->nsDef = ns;
814 xmlAddChild((xmlNodePtr) doc, catalog);
815
816 /*
817 * add all the catalog entries
818 */
819 cur = catal;
820 while (cur != NULL) {
821 switch (cur->type) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000822 case XML_CATA_BROKEN_CATALOG:
Daniel Veillard344cee72001-08-20 00:08:40 +0000823 case XML_CATA_CATALOG:
824 if (cur == catal) {
825 cur = cur->children;
826 continue;
827 }
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000828 break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000829 case XML_CATA_NEXT_CATALOG:
830 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
831 xmlSetProp(node, BAD_CAST "catalog", cur->value);
832 xmlAddChild(catalog, node);
833 break;
834 case XML_CATA_NONE:
835 break;
836 case XML_CATA_PUBLIC:
837 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
838 xmlSetProp(node, BAD_CAST "publicId", cur->name);
839 xmlSetProp(node, BAD_CAST "uri", cur->value);
840 xmlAddChild(catalog, node);
841 break;
842 case XML_CATA_SYSTEM:
843 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
844 xmlSetProp(node, BAD_CAST "systemId", cur->name);
845 xmlSetProp(node, BAD_CAST "uri", cur->value);
846 xmlAddChild(catalog, node);
847 break;
848 case XML_CATA_REWRITE_SYSTEM:
849 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
850 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
851 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
852 xmlAddChild(catalog, node);
853 break;
854 case XML_CATA_DELEGATE_PUBLIC:
855 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
856 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
857 xmlSetProp(node, BAD_CAST "catalog", cur->value);
858 xmlAddChild(catalog, node);
859 break;
860 case XML_CATA_DELEGATE_SYSTEM:
861 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
862 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
863 xmlSetProp(node, BAD_CAST "catalog", cur->value);
864 xmlAddChild(catalog, node);
865 break;
866 case XML_CATA_URI:
867 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
868 xmlSetProp(node, BAD_CAST "name", cur->name);
869 xmlSetProp(node, BAD_CAST "uri", cur->value);
870 xmlAddChild(catalog, node);
871 break;
872 case XML_CATA_REWRITE_URI:
873 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
874 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
875 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
876 xmlAddChild(catalog, node);
877 break;
878 case XML_CATA_DELEGATE_URI:
879 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
880 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
881 xmlSetProp(node, BAD_CAST "catalog", cur->value);
882 xmlAddChild(catalog, node);
883 break;
884 case SGML_CATA_SYSTEM:
885 case SGML_CATA_PUBLIC:
886 case SGML_CATA_ENTITY:
887 case SGML_CATA_PENTITY:
888 case SGML_CATA_DOCTYPE:
889 case SGML_CATA_LINKTYPE:
890 case SGML_CATA_NOTATION:
891 case SGML_CATA_DELEGATE:
892 case SGML_CATA_BASE:
893 case SGML_CATA_CATALOG:
894 case SGML_CATA_DOCUMENT:
895 case SGML_CATA_SGMLDECL:
896 break;
897 }
898 cur = cur->next;
899 }
900
901 /*
902 * reserialize it
903 */
904 buf = xmlOutputBufferCreateFile(out, NULL);
905 if (buf == NULL) {
906 xmlFreeDoc(doc);
907 return(-1);
908 }
909 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
910
911 /*
912 * Free it
913 */
914 xmlFreeDoc(doc);
915
916 return(ret);
917}
918
919/**
920 * xmlAddXMLCatalog:
921 * @catal: top of an XML catalog
922 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +0000923 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +0000924 * @replace: the replacement value for the match
925 *
926 * Add an entry in the XML catalog, it may overwrite existing but
927 * different entries.
928 *
929 * Returns 0 if successful, -1 otherwise
930 */
931static int
932xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
933 const xmlChar *orig, const xmlChar *replace) {
934 xmlCatalogEntryPtr cur;
935 xmlCatalogEntryType typ;
936
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000937 if ((catal == NULL) ||
938 ((catal->type != XML_CATA_CATALOG) &&
939 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +0000940 return(-1);
941 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000942 if (typ == XML_CATA_NONE) {
943 if (xmlDebugCatalogs)
944 xmlGenericError(xmlGenericErrorContext,
945 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +0000946 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000947 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000948
949 cur = catal->children;
950 /*
951 * Might be a simple "update in place"
952 */
953 if (cur != NULL) {
954 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000955 if ((orig != NULL) && (cur->type == typ) &&
956 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000957 if (xmlDebugCatalogs)
958 xmlGenericError(xmlGenericErrorContext,
959 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +0000960 if (cur->value != NULL)
961 xmlFree(cur->value);
962 cur->value = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +0000963 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +0000964 }
965 if (cur->next == NULL)
966 break;
967 cur = cur->next;
968 }
969 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000970 if (xmlDebugCatalogs)
971 xmlGenericError(xmlGenericErrorContext,
972 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +0000973 if (cur == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000974 catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillard344cee72001-08-20 00:08:40 +0000975 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000976 cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
Daniel Veillardcda96922001-08-21 10:56:31 +0000977 return(0);
978}
979
980/**
981 * xmlDelXMLCatalog:
982 * @catal: top of an XML catalog
983 * @value: the value to remove from teh catalog
984 *
985 * Remove entries in the XML catalog where the value or the URI
986 * is equal to @value
987 *
988 * Returns the number of entries removed if successful, -1 otherwise
989 */
990static int
991xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
992 xmlCatalogEntryPtr cur, prev, tmp;
993 int ret = 0;
994
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000995 if ((catal == NULL) ||
996 ((catal->type != XML_CATA_CATALOG) &&
997 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +0000998 return(-1);
999 if (value == NULL)
1000 return(-1);
1001
1002 /*
1003 * Scan the children
1004 */
1005 cur = catal->children;
1006 prev = NULL;
1007 while (cur != NULL) {
1008 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1009 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001010 if (xmlDebugCatalogs) {
1011 if (cur->name != NULL)
1012 xmlGenericError(xmlGenericErrorContext,
1013 "Removing element %s from catalog\n", cur->name);
1014 else
1015 xmlGenericError(xmlGenericErrorContext,
1016 "Removing element %s from catalog\n", cur->value);
1017 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001018 ret++;
1019 tmp = cur;
1020 cur = tmp->next;
1021 if (prev == NULL) {
1022 catal->children = cur;
1023 } else {
1024 prev->next = cur;
1025 }
1026 xmlFreeCatalogEntry(tmp);
1027 continue;
1028 }
1029 prev = cur;
1030 cur = cur->next;
1031 }
1032 return(ret);
1033}
1034
1035/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001036 * xmlCatalogXMLResolve:
1037 * @catal: a catalog list
1038 * @pubId: the public ID string
1039 * @sysId: the system ID string
1040 *
1041 * Do a complete resolution lookup of an External Identifier for a
1042 * list of catalog entries.
1043 *
1044 * Implements (or tries to) 7.1. External Identifier Resolution
1045 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1046 *
1047 * Returns the URI of the resource or NULL if not found
1048 */
1049static xmlChar *
1050xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1051 const xmlChar *sysID) {
1052 xmlChar *ret = NULL;
1053 xmlCatalogEntryPtr cur;
1054 int haveDelegate = 0;
1055 int haveNext = 0;
1056
1057 /*
1058 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1059 */
1060 if (sysID != NULL) {
1061 xmlCatalogEntryPtr rewrite = NULL;
1062 int lenrewrite = 0, len;
1063 cur = catal;
1064 haveDelegate = 0;
1065 while (cur != NULL) {
1066 switch (cur->type) {
1067 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001068 if (xmlStrEqual(sysID, cur->name)) {
1069 if (xmlDebugCatalogs)
1070 xmlGenericError(xmlGenericErrorContext,
1071 "Found system match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001072 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001073 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001074 break;
1075 case XML_CATA_REWRITE_SYSTEM:
1076 len = xmlStrlen(cur->name);
1077 if ((len > lenrewrite) &&
1078 (!xmlStrncmp(sysID, cur->name, len))) {
1079 lenrewrite = len;
1080 rewrite = cur;
1081 }
1082 break;
1083 case XML_CATA_DELEGATE_SYSTEM:
1084 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1085 haveDelegate++;
1086 break;
1087 case XML_CATA_NEXT_CATALOG:
1088 haveNext++;
1089 break;
1090 default:
1091 break;
1092 }
1093 cur = cur->next;
1094 }
1095 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001096 if (xmlDebugCatalogs)
1097 xmlGenericError(xmlGenericErrorContext,
1098 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001099 ret = xmlStrdup(rewrite->value);
1100 if (ret != NULL)
1101 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1102 return(ret);
1103 }
1104 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001105 const xmlChar *delegates[MAX_DELEGATE];
1106 int nbList = 0, i;
1107
Daniel Veillardcda96922001-08-21 10:56:31 +00001108 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001109 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001110 * matches when the list was produced.
1111 */
1112 cur = catal;
1113 while (cur != NULL) {
1114 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1115 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001116 for (i = 0;i < nbList;i++)
1117 if (xmlStrEqual(cur->value, delegates[i]))
1118 break;
1119 if (i < nbList) {
1120 cur = cur->next;
1121 continue;
1122 }
1123 if (nbList < MAX_DELEGATE)
1124 delegates[nbList++] = cur->value;
1125
Daniel Veillardcda96922001-08-21 10:56:31 +00001126 if (cur->children == NULL) {
1127 xmlFetchXMLCatalogFile(cur);
1128 }
1129 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001130 if (xmlDebugCatalogs)
1131 xmlGenericError(xmlGenericErrorContext,
1132 "Trying system delegate %s\n", cur->value);
1133 ret = xmlCatalogListXMLResolve(cur->children, NULL,
1134 sysID);
1135 if (ret != NULL)
1136 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001137 }
1138 }
1139 cur = cur->next;
1140 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001141 /*
1142 * Apply the cut algorithm explained in 4/
1143 */
1144 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001145 }
1146 }
1147 /*
1148 * Then tries 5/ 6/ if a public ID is provided
1149 */
1150 if (pubID != NULL) {
1151 cur = catal;
1152 haveDelegate = 0;
1153 while (cur != NULL) {
1154 switch (cur->type) {
1155 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001156 if (xmlStrEqual(pubID, cur->name)) {
1157 if (xmlDebugCatalogs)
1158 xmlGenericError(xmlGenericErrorContext,
1159 "Found public match %s\n", cur->name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001160 return(xmlStrdup(cur->value));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001161 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001162 break;
1163 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001164 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1165 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001166 haveDelegate++;
1167 break;
1168 case XML_CATA_NEXT_CATALOG:
1169 if (sysID == NULL)
1170 haveNext++;
1171 break;
1172 default:
1173 break;
1174 }
1175 cur = cur->next;
1176 }
1177 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001178 const xmlChar *delegates[MAX_DELEGATE];
1179 int nbList = 0, i;
1180
Daniel Veillardcda96922001-08-21 10:56:31 +00001181 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001182 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001183 * matches when the list was produced.
1184 */
1185 cur = catal;
1186 while (cur != NULL) {
1187 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001188 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1189 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001190
1191 for (i = 0;i < nbList;i++)
1192 if (xmlStrEqual(cur->value, delegates[i]))
1193 break;
1194 if (i < nbList) {
1195 cur = cur->next;
1196 continue;
1197 }
1198 if (nbList < MAX_DELEGATE)
1199 delegates[nbList++] = cur->value;
1200
Daniel Veillardcda96922001-08-21 10:56:31 +00001201 if (cur->children == NULL) {
1202 xmlFetchXMLCatalogFile(cur);
1203 }
1204 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001205 if (xmlDebugCatalogs)
1206 xmlGenericError(xmlGenericErrorContext,
1207 "Trying public delegate %s\n", cur->value);
1208 ret = xmlCatalogListXMLResolve(cur->children, pubID,
1209 NULL);
1210 if (ret != NULL)
1211 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001212 }
1213 }
1214 cur = cur->next;
1215 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001216 /*
1217 * Apply the cut algorithm explained in 4/
1218 */
1219 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001220 }
1221 }
1222 if (haveNext) {
1223 cur = catal;
1224 while (cur != NULL) {
1225 if (cur->type == XML_CATA_NEXT_CATALOG) {
1226 if (cur->children == NULL) {
1227 xmlFetchXMLCatalogFile(cur);
1228 }
1229 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001230 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1231 if (ret != NULL)
1232 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001233 }
1234 }
1235 cur = cur->next;
1236 }
1237 }
1238
1239 return(NULL);
1240}
1241
1242/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001243 * xmlCatalogXMLResolveURI:
1244 * @catal: a catalog list
1245 * @URI: the URI
1246 * @sysId: the system ID string
1247 *
1248 * Do a complete resolution lookup of an External Identifier for a
1249 * list of catalog entries.
1250 *
1251 * Implements (or tries to) 7.2.2. URI Resolution
1252 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1253 *
1254 * Returns the URI of the resource or NULL if not found
1255 */
1256static xmlChar *
1257xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1258 xmlChar *ret = NULL;
1259 xmlCatalogEntryPtr cur;
1260 int haveDelegate = 0;
1261 int haveNext = 0;
1262 xmlCatalogEntryPtr rewrite = NULL;
1263 int lenrewrite = 0, len;
1264
1265 if (catal == NULL)
1266 return(NULL);
1267
1268 if (URI == NULL)
1269 return(NULL);
1270
1271 /*
1272 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1273 */
1274 cur = catal;
1275 haveDelegate = 0;
1276 while (cur != NULL) {
1277 switch (cur->type) {
1278 case XML_CATA_URI:
1279 if (xmlStrEqual(URI, cur->name)) {
1280 if (xmlDebugCatalogs)
1281 xmlGenericError(xmlGenericErrorContext,
1282 "Found URI match %s\n", cur->name);
1283 return(xmlStrdup(cur->value));
1284 }
1285 break;
1286 case XML_CATA_REWRITE_URI:
1287 len = xmlStrlen(cur->name);
1288 if ((len > lenrewrite) &&
1289 (!xmlStrncmp(URI, cur->name, len))) {
1290 lenrewrite = len;
1291 rewrite = cur;
1292 }
1293 break;
1294 case XML_CATA_DELEGATE_URI:
1295 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1296 haveDelegate++;
1297 break;
1298 case XML_CATA_NEXT_CATALOG:
1299 haveNext++;
1300 break;
1301 default:
1302 break;
1303 }
1304 cur = cur->next;
1305 }
1306 if (rewrite != NULL) {
1307 if (xmlDebugCatalogs)
1308 xmlGenericError(xmlGenericErrorContext,
1309 "Using rewriting rule %s\n", rewrite->name);
1310 ret = xmlStrdup(rewrite->value);
1311 if (ret != NULL)
1312 ret = xmlStrcat(ret, &URI[lenrewrite]);
1313 return(ret);
1314 }
1315 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001316 const xmlChar *delegates[MAX_DELEGATE];
1317 int nbList = 0, i;
1318
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001319 /*
1320 * Assume the entries have been sorted by decreasing substring
1321 * matches when the list was produced.
1322 */
1323 cur = catal;
1324 while (cur != NULL) {
1325 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1326 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001327 for (i = 0;i < nbList;i++)
1328 if (xmlStrEqual(cur->value, delegates[i]))
1329 break;
1330 if (i < nbList) {
1331 cur = cur->next;
1332 continue;
1333 }
1334 if (nbList < MAX_DELEGATE)
1335 delegates[nbList++] = cur->value;
1336
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001337 if (cur->children == NULL) {
1338 xmlFetchXMLCatalogFile(cur);
1339 }
1340 if (cur->children != NULL) {
1341 if (xmlDebugCatalogs)
1342 xmlGenericError(xmlGenericErrorContext,
1343 "Trying URI delegate %s\n", cur->value);
1344 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1345 if (ret != NULL)
1346 return(ret);
1347 }
1348 }
1349 cur = cur->next;
1350 }
1351 /*
1352 * Apply the cut algorithm explained in 4/
1353 */
1354 return(XML_CATAL_BREAK);
1355 }
1356 if (haveNext) {
1357 cur = catal;
1358 while (cur != NULL) {
1359 if (cur->type == XML_CATA_NEXT_CATALOG) {
1360 if (cur->children == NULL) {
1361 xmlFetchXMLCatalogFile(cur);
1362 }
1363 if (cur->children != NULL) {
1364 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1365 if (ret != NULL)
1366 return(ret);
1367 }
1368 }
1369 cur = cur->next;
1370 }
1371 }
1372
1373 return(NULL);
1374}
1375
1376/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001377 * xmlCatalogListXMLResolve:
1378 * @catal: a catalog list
1379 * @pubId: the public ID string
1380 * @sysId: the system ID string
1381 *
1382 * Do a complete resolution lookup of an External Identifier for a
1383 * list of catalogs
1384 *
1385 * Implements (or tries to) 7.1. External Identifier Resolution
1386 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1387 *
1388 * Returns the URI of the resource or NULL if not found
1389 */
1390static xmlChar *
1391xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1392 const xmlChar *sysID) {
1393 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001394 xmlChar *urnID = NULL;
1395
1396 if (catal == NULL)
1397 return(NULL);
1398 if ((pubID == NULL) && (sysID == NULL))
1399 return(NULL);
1400
1401 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1402 urnID = xmlCatalogUnWrapURN(pubID);
1403 if (xmlDebugCatalogs) {
1404 if (urnID == NULL)
1405 xmlGenericError(xmlGenericErrorContext,
1406 "Public URN ID %s expanded to NULL\n", pubID);
1407 else
1408 xmlGenericError(xmlGenericErrorContext,
1409 "Public URN ID expanded to %s\n", urnID);
1410 }
1411 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
1412 if (urnID != NULL)
1413 xmlFree(urnID);
1414 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001415 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001416 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1417 urnID = xmlCatalogUnWrapURN(sysID);
1418 if (xmlDebugCatalogs) {
1419 if (urnID == NULL)
1420 xmlGenericError(xmlGenericErrorContext,
1421 "System URN ID %s expanded to NULL\n", sysID);
1422 else
1423 xmlGenericError(xmlGenericErrorContext,
1424 "System URN ID expanded to %s\n", urnID);
1425 }
1426 if (pubID == NULL)
1427 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1428 else if (xmlStrEqual(pubID, urnID))
1429 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1430 else {
1431 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
1432 }
1433 if (urnID != NULL)
1434 xmlFree(urnID);
1435 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00001436 }
1437 while (catal != NULL) {
1438 if (catal->type == XML_CATA_CATALOG) {
1439 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001440 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00001441 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001442 if (catal->children != NULL) {
1443 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
1444 if (ret != NULL)
1445 return(ret);
1446 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001447 }
1448 catal = catal->next;
1449 }
1450 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00001451}
1452
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001453/**
1454 * xmlCatalogListXMLResolveURI:
1455 * @catal: a catalog list
1456 * @URI: the URI
1457 *
1458 * Do a complete resolution lookup of an URI for a list of catalogs
1459 *
1460 * Implements (or tries to) 7.2. URI Resolution
1461 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1462 *
1463 * Returns the URI of the resource or NULL if not found
1464 */
1465static xmlChar *
1466xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1467 xmlChar *ret = NULL;
1468 xmlChar *urnID = NULL;
1469
1470 if (catal == NULL)
1471 return(NULL);
1472 if (URI == NULL)
1473 return(NULL);
1474
1475 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
1476 urnID = xmlCatalogUnWrapURN(URI);
1477 if (xmlDebugCatalogs) {
1478 if (urnID == NULL)
1479 xmlGenericError(xmlGenericErrorContext,
1480 "URN ID %s expanded to NULL\n", URI);
1481 else
1482 xmlGenericError(xmlGenericErrorContext,
1483 "URN ID expanded to %s\n", urnID);
1484 }
1485 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
1486 if (urnID != NULL)
1487 xmlFree(urnID);
1488 return(ret);
1489 }
1490 while (catal != NULL) {
1491 if (catal->type == XML_CATA_CATALOG) {
1492 if (catal->children == NULL) {
1493 xmlFetchXMLCatalogFile(catal);
1494 }
1495 if (catal->children != NULL) {
1496 ret = xmlCatalogXMLResolveURI(catal->children, URI);
1497 if (ret != NULL)
1498 return(ret);
1499 }
1500 }
1501 catal = catal->next;
1502 }
1503 return(ret);
1504}
1505
Daniel Veillard344cee72001-08-20 00:08:40 +00001506/************************************************************************
1507 * *
1508 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00001509 * *
1510 ************************************************************************/
1511
1512
1513#define RAW *cur
1514#define NEXT cur++;
1515#define SKIP(x) cur += x;
1516
1517#define SKIP_BLANKS while (IS_BLANK(*cur)) NEXT;
1518
1519static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001520xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001521 if ((cur[0] != '-') || (cur[1] != '-'))
1522 return(cur);
1523 SKIP(2);
1524 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
1525 NEXT;
1526 if (cur[0] == 0) {
1527 return(NULL);
1528 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001529 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00001530}
1531
1532static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001533xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001534 xmlChar *buf = NULL;
1535 int len = 0;
1536 int size = 50;
1537 xmlChar stop;
1538 int count = 0;
1539
1540 *id = NULL;
1541
1542 if (RAW == '"') {
1543 NEXT;
1544 stop = '"';
1545 } else if (RAW == '\'') {
1546 NEXT;
1547 stop = '\'';
1548 } else {
1549 stop = ' ';
1550 }
1551 buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
1552 if (buf == NULL) {
1553 xmlGenericError(xmlGenericErrorContext,
1554 "malloc of %d byte failed\n", size);
1555 return(NULL);
1556 }
1557 while (xmlIsPubidChar(*cur)) {
1558 if ((*cur == stop) && (stop != ' '))
1559 break;
1560 if ((stop == ' ') && (IS_BLANK(*cur)))
1561 break;
1562 if (len + 1 >= size) {
1563 size *= 2;
1564 buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
1565 if (buf == NULL) {
1566 xmlGenericError(xmlGenericErrorContext,
1567 "realloc of %d byte failed\n", size);
1568 return(NULL);
1569 }
1570 }
1571 buf[len++] = *cur;
1572 count++;
1573 NEXT;
1574 }
1575 buf[len] = 0;
1576 if (stop == ' ') {
1577 if (!IS_BLANK(*cur)) {
1578 xmlFree(buf);
1579 return(NULL);
1580 }
1581 } else {
1582 if (*cur != stop) {
1583 xmlFree(buf);
1584 return(NULL);
1585 }
1586 NEXT;
1587 }
1588 *id = buf;
1589 return(cur);
1590}
1591
1592static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00001593xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001594 xmlChar buf[XML_MAX_NAMELEN + 5];
1595 int len = 0;
1596 int c;
1597
1598 *name = NULL;
1599
1600 /*
1601 * Handler for more complex cases
1602 */
1603 c = *cur;
1604 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
1605 return(NULL);
1606 }
1607
1608 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
1609 (c == '.') || (c == '-') ||
1610 (c == '_') || (c == ':'))) {
1611 buf[len++] = c;
1612 cur++;
1613 c = *cur;
1614 if (len >= XML_MAX_NAMELEN)
1615 return(NULL);
1616 }
1617 *name = xmlStrndup(buf, len);
1618 return(cur);
1619}
1620
Daniel Veillard344cee72001-08-20 00:08:40 +00001621static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00001622xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001623 xmlCatalogEntryType type = XML_CATA_NONE;
1624 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
1625 type = SGML_CATA_SYSTEM;
1626 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
1627 type = SGML_CATA_PUBLIC;
1628 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1629 type = SGML_CATA_DELEGATE;
1630 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
1631 type = SGML_CATA_ENTITY;
1632 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
1633 type = SGML_CATA_DOCTYPE;
1634 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
1635 type = SGML_CATA_LINKTYPE;
1636 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
1637 type = SGML_CATA_NOTATION;
1638 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
1639 type = SGML_CATA_SGMLDECL;
1640 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
1641 type = SGML_CATA_DOCUMENT;
1642 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
1643 type = SGML_CATA_CATALOG;
1644 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
1645 type = SGML_CATA_BASE;
1646 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
1647 type = SGML_CATA_DELEGATE;
1648 return(type);
1649}
1650
Daniel Veillarda7374592001-05-10 14:17:55 +00001651static int
Daniel Veillardcda96922001-08-21 10:56:31 +00001652xmlParseSGMLCatalog(const xmlChar *value, const char *file) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001653 const xmlChar *cur = value;
1654 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001655 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00001656
1657 if ((cur == NULL) || (file == NULL))
1658 return(-1);
1659 base = xmlStrdup((const xmlChar *) file);
1660
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00001661 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001662 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00001663 if (cur[0] == 0)
1664 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00001665 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001666 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00001667 if (cur == NULL) {
1668 /* error */
1669 break;
1670 }
1671 } else {
1672 xmlChar *sysid = NULL;
1673 xmlChar *name = NULL;
1674 xmlCatalogEntryType type = XML_CATA_NONE;
1675
Daniel Veillardcda96922001-08-21 10:56:31 +00001676 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001677 if (name == NULL) {
1678 /* error */
1679 break;
1680 }
1681 if (!IS_BLANK(*cur)) {
1682 /* error */
1683 break;
1684 }
1685 SKIP_BLANKS;
1686 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001687 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00001688 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001689 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00001690 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001691 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001692 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001693 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00001694 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001695 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001696 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001697 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001698 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001699 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00001700 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001701 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001702 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001703 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00001704 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001705 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00001706 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001707 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001708 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00001709 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00001710 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
1711 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00001712 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001713 if (name == NULL) {
1714 /* error */
1715 break;
1716 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001717 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001718 continue;
1719 }
1720 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001721 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00001722
1723 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001724 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00001725 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00001726 type = SGML_CATA_PENTITY;
1727 case SGML_CATA_PENTITY:
1728 case SGML_CATA_DOCTYPE:
1729 case SGML_CATA_LINKTYPE:
1730 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00001731 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001732 if (cur == NULL) {
1733 /* error */
1734 break;
1735 }
1736 if (!IS_BLANK(*cur)) {
1737 /* error */
1738 break;
1739 }
1740 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001741 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001742 if (cur == NULL) {
1743 /* error */
1744 break;
1745 }
1746 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001747 case SGML_CATA_PUBLIC:
1748 case SGML_CATA_SYSTEM:
1749 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00001750 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00001751 if (cur == NULL) {
1752 /* error */
1753 break;
1754 }
1755 if (!IS_BLANK(*cur)) {
1756 /* error */
1757 break;
1758 }
1759 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00001760 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001761 if (cur == NULL) {
1762 /* error */
1763 break;
1764 }
1765 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001766 case SGML_CATA_BASE:
1767 case SGML_CATA_CATALOG:
1768 case SGML_CATA_DOCUMENT:
1769 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00001770 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001771 if (cur == NULL) {
1772 /* error */
1773 break;
1774 }
1775 break;
1776 default:
1777 break;
1778 }
1779 if (cur == NULL) {
1780 if (name != NULL)
1781 xmlFree(name);
1782 if (sysid != NULL)
1783 xmlFree(sysid);
1784 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00001785 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001786 if (base != NULL)
1787 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001788 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00001789 } else if ((type == SGML_CATA_PUBLIC) ||
1790 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00001791 xmlChar *filename;
1792
1793 filename = xmlBuildURI(sysid, base);
1794 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001795 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00001796
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001797 entry = xmlNewCatalogEntry(type, name, filename,
1798 XML_CATA_PREFER_NONE);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001799 res = xmlHashAddEntry(xmlDefaultCatalog, name, entry);
1800 if (res < 0) {
1801 xmlFreeCatalogEntry(entry);
1802 }
1803 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00001804 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001805
Daniel Veillard344cee72001-08-20 00:08:40 +00001806 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001807 xmlChar *filename;
1808
1809 filename = xmlBuildURI(sysid, base);
1810 if (filename != NULL) {
1811 xmlLoadCatalog((const char *)filename);
1812 xmlFree(filename);
1813 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001814 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001815 /*
1816 * drop anything else we won't handle it
1817 */
1818 if (name != NULL)
1819 xmlFree(name);
1820 if (sysid != NULL)
1821 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00001822 }
1823 }
1824 if (base != NULL)
1825 xmlFree(base);
1826 if (cur == NULL)
1827 return(-1);
1828 return(0);
1829}
1830
Daniel Veillardcda96922001-08-21 10:56:31 +00001831/**
1832 * xmlCatalogGetSGMLPublic:
1833 * @catal: an SGML catalog hash
1834 * @pubId: the public ID string
1835 *
1836 * Try to lookup the system ID associated to a public ID
1837 *
1838 * Returns the system ID if found or NULL otherwise.
1839 */
1840static const xmlChar *
1841xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
1842 xmlCatalogEntryPtr entry;
1843
1844 if (catal == NULL)
1845 return(NULL);
1846
1847 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
1848 if (entry == NULL)
1849 return(NULL);
1850 if (entry->type == SGML_CATA_PUBLIC)
1851 return(entry->value);
1852 return(NULL);
1853}
1854
1855/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001856 * xmlCatalogGetSGMLSystem:
1857 * @catal: an SGML catalog hash
1858 * @sysId: the public ID string
1859 *
1860 * Try to lookup the catalog local reference for a system ID
1861 *
1862 * Returns the system ID if found or NULL otherwise.
1863 */
1864static const xmlChar *
1865xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
1866 xmlCatalogEntryPtr entry;
1867
1868 if (catal == NULL)
1869 return(NULL);
1870
1871 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
1872 if (entry == NULL)
1873 return(NULL);
1874 if (entry->type == SGML_CATA_SYSTEM)
1875 return(entry->value);
1876 return(NULL);
1877}
1878
1879/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001880 * xmlCatalogSGMLResolve:
1881 * @pubId: the public ID string
1882 * @sysId: the system ID string
1883 *
1884 * Do a complete resolution lookup of an External Identifier
1885 *
1886 * Returns the URI of the resource or NULL if not found
1887 */
1888static const xmlChar *
1889xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00001890 const xmlChar *ret = NULL;
1891
1892 if (xmlDefaultCatalog == NULL)
1893 return(NULL);
1894
1895 if (pubID != NULL)
1896 ret = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
1897 if (ret != NULL)
1898 return(ret);
1899 if (sysID != NULL)
1900 ret = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
Daniel Veillardcda96922001-08-21 10:56:31 +00001901 return(NULL);
1902}
1903
Daniel Veillarda7374592001-05-10 14:17:55 +00001904/************************************************************************
1905 * *
1906 * Public interfaces *
1907 * *
1908 ************************************************************************/
1909
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001910/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001911 * xmlInitializeCatalog:
1912 *
1913 * Do the catalog initialization.
1914 * TODO: this function is not thread safe, catalog initialization should
1915 * preferably be done once at startup
1916 */
1917void
1918xmlInitializeCatalog(void) {
1919 const char *catalogs;
1920
1921 if (xmlCatalogInitialized != 0)
1922 return;
1923
1924 if (getenv("XML_DEBUG_CATALOG"))
1925 xmlDebugCatalogs = 1;
1926 if ((xmlDefaultXMLCatalogList == NULL) && (xmlDefaultCatalog == NULL)) {
1927 catalogs = getenv("XML_CATALOG_FILES");
1928 if (catalogs == NULL)
1929 catalogs = XML_DEFAULT_CATALOG;
1930 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
1931 NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
1932 }
1933
1934 xmlCatalogInitialized = 1;
1935}
1936
1937/**
Daniel Veillarda7374592001-05-10 14:17:55 +00001938 * xmlLoadCatalog:
1939 * @filename: a file path
1940 *
Daniel Veillard81418e32001-05-22 15:08:55 +00001941 * Load the catalog and makes its definitions effective for the default
1942 * external entity loader. It will recuse in CATALOG entries.
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001943 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001944 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00001945 *
1946 * Returns 0 in case of success -1 in case of error
1947 */
1948int
1949xmlLoadCatalog(const char *filename) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001950 int fd, len, ret, i;
Daniel Veillarda7374592001-05-10 14:17:55 +00001951 struct stat info;
1952 xmlChar *content;
1953
1954 if (filename == NULL)
1955 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001956
Daniel Veillarda7374592001-05-10 14:17:55 +00001957 if (xmlDefaultCatalog == NULL)
1958 xmlDefaultCatalog = xmlHashCreate(20);
1959 if (xmlDefaultCatalog == NULL)
1960 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001961
1962 /*
1963 * Need to be done after ...
1964 */
1965 if (!xmlCatalogInitialized)
1966 xmlInitializeCatalog();
1967
1968#ifdef HAVE_STAT
Daniel Veillarda7374592001-05-10 14:17:55 +00001969 if (stat(filename, &info) < 0)
1970 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001971#endif
Daniel Veillarda7374592001-05-10 14:17:55 +00001972
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001973 /*
1974 * Prevent loops
1975 */
1976 for (i = 0;i < catalNr;i++) {
Daniel Veillard81418e32001-05-22 15:08:55 +00001977 if (xmlStrEqual((const xmlChar *)catalTab[i],
1978 (const xmlChar *)filename)) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001979 xmlGenericError(xmlGenericErrorContext,
1980 "xmlLoadCatalog: %s seems to induce a loop\n",
1981 filename);
1982 return(-1);
1983 }
1984 }
1985 if (catalNr >= catalMax) {
1986 xmlGenericError(xmlGenericErrorContext,
1987 "xmlLoadCatalog: %s catalog list too deep\n",
1988 filename);
1989 return(-1);
1990 }
1991 catalTab[catalNr++] = filename;
1992
1993 if ((fd = open(filename, O_RDONLY)) < 0) {
1994 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00001995 return(-1);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00001996 }
Daniel Veillarda7374592001-05-10 14:17:55 +00001997
1998 content = xmlMalloc(info.st_size + 10);
1999 if (content == NULL) {
2000 xmlGenericError(xmlGenericErrorContext,
2001 "realloc of %d byte failed\n", info.st_size + 10);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002002 catalNr--;
2003 return(-1);
Daniel Veillarda7374592001-05-10 14:17:55 +00002004 }
2005 len = read(fd, content, info.st_size);
2006 if (len < 0) {
2007 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002008 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00002009 return(-1);
2010 }
2011 content[len] = 0;
2012 close(fd);
2013
Daniel Veillard344cee72001-08-20 00:08:40 +00002014 if ((content[0] == ' ') || (content[0] == '-') ||
2015 ((content[0] >= 'A') && (content[0] <= 'Z')) ||
2016 ((content[0] >= 'a') && (content[0] <= 'z')))
Daniel Veillardcda96922001-08-21 10:56:31 +00002017 ret = xmlParseSGMLCatalog(content, filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00002018 else {
2019 xmlCatalogEntryPtr catal, tmp;
2020 /* TODO: allow to switch the default preference */
2021 catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename);
2022 if (catal != NULL) {
2023 if (xmlDefaultXMLCatalogList == NULL)
2024 xmlDefaultXMLCatalogList = catal;
2025 else {
2026 tmp = xmlDefaultXMLCatalogList;
2027 while (tmp->next != NULL)
2028 tmp = tmp->next;
2029 tmp->next = catal;
2030 }
2031 ret = 0;
2032 } else
2033 ret = -1;
2034 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002035 xmlFree(content);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002036 catalNr--;
Daniel Veillarda7374592001-05-10 14:17:55 +00002037 return(ret);
2038}
2039
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002040/**
Daniel Veillard81418e32001-05-22 15:08:55 +00002041 * xmlLoadCatalogs:
2042 * @paths: a list of file path separated by ':' or spaces
2043 *
2044 * Load the catalogs and makes their definitions effective for the default
2045 * external entity loader.
2046 * TODO: this function is not thread safe, catalog initialization should
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002047 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00002048 */
2049void
2050xmlLoadCatalogs(const char *pathss) {
2051 const char *cur;
2052 const char *paths;
2053 xmlChar *path;
2054
2055 cur = pathss;
2056 while ((cur != NULL) && (*cur != 0)) {
2057 while (IS_BLANK(*cur)) cur++;
2058 if (*cur != 0) {
2059 paths = cur;
2060 while ((*cur != 0) && (*cur != ':') && (!IS_BLANK(*cur)))
2061 cur++;
2062 path = xmlStrndup((const xmlChar *)paths, cur - paths);
2063 if (path != NULL) {
2064 xmlLoadCatalog((const char *) path);
2065 xmlFree(path);
2066 }
2067 }
2068 while (*cur == ':')
2069 cur++;
2070 }
2071}
2072
Daniel Veillarda7374592001-05-10 14:17:55 +00002073/**
2074 * xmlCatalogCleanup:
2075 *
2076 * Free up all the memory associated with catalogs
2077 */
2078void
2079xmlCatalogCleanup(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002080 if (xmlDebugCatalogs)
2081 xmlGenericError(xmlGenericErrorContext,
2082 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00002083 if (xmlCatalogXMLFiles != NULL)
2084 xmlHashFree(xmlCatalogXMLFiles, NULL);
2085 xmlCatalogXMLFiles = NULL;
Daniel Veillardcda96922001-08-21 10:56:31 +00002086 if (xmlDefaultXMLCatalogList != NULL)
2087 xmlFreeCatalogEntryList(xmlDefaultXMLCatalogList);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002088 xmlDefaultXMLCatalogList = NULL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002089 xmlDefaultXMLCatalogList = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002090 if (xmlDefaultCatalog != NULL)
2091 xmlHashFree(xmlDefaultCatalog,
2092 (xmlHashDeallocator) xmlFreeCatalogEntry);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002093 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002094 xmlDebugCatalogs = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00002095 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002096 xmlCatalogInitialized = 0;
Daniel Veillarda7374592001-05-10 14:17:55 +00002097}
2098
2099/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002100 * xmlCatalogGetSystem:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002101 * @pubId: the public ID string
Daniel Veillarda7374592001-05-10 14:17:55 +00002102 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002103 * Try to lookup the system ID associated to a public ID
2104 * DEPRECATED, use xmlCatalogResolveSystem()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002105 *
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002106 * Returns the system ID if found or NULL otherwise.
Daniel Veillarda7374592001-05-10 14:17:55 +00002107 */
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002108const xmlChar *
2109xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002110 xmlChar *ret;
2111 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002112
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002113 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002114 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002115
2116 if (!xmlCatalogInitialized)
2117 xmlInitializeCatalog();
2118
2119 /*
2120 * Check first the XML catalogs
2121 */
2122 if (xmlDefaultXMLCatalogList != NULL) {
2123 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
2124 if (ret != NULL) {
2125 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
2126 result[sizeof(result) - 1] = 0;
2127 return(result);
2128 }
2129 }
2130
2131 if (xmlDefaultCatalog != NULL)
2132 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID));
2133 return(NULL);
2134}
2135
2136/**
2137 * xmlCatalogResolveSystem:
2138 * @sysId: the public ID string
2139 *
2140 * Try to lookup the catalog resource for a system ID
2141 *
2142 * Returns the system ID if found or NULL otherwise, the value returned
2143 * must be freed by the caller.
2144 */
2145xmlChar *
2146xmlCatalogResolveSystem(const xmlChar *sysID) {
2147 xmlCatalogEntryPtr catal;
2148 xmlChar *ret;
2149 const xmlChar *sgml;
2150
2151 if (sysID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002152 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002153
2154 if (!xmlCatalogInitialized)
2155 xmlInitializeCatalog();
2156
2157 /*
2158 * Check first the XML catalogs
2159 */
2160 catal = xmlDefaultXMLCatalogList;
2161 if (catal != NULL) {
2162 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
2163 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2164 return(ret);
2165 }
2166
2167 if (xmlDefaultCatalog != NULL) {
2168 sgml = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
2169 if (sgml != NULL)
2170 return(xmlStrdup(sgml));
2171 }
Daniel Veillard344cee72001-08-20 00:08:40 +00002172 return(NULL);
2173}
2174
2175/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002176 * xmlCatalogGetPublic:
2177 * @pubId: the public ID string
2178 *
2179 * Try to lookup the system ID associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002180 * DEPRECATED, use xmlCatalogResolvePublic()
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002181 *
2182 * Returns the system ID if found or NULL otherwise.
2183 */
2184const xmlChar *
2185xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002186 xmlChar *ret;
2187 static xmlChar result[1000];
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002188
Daniel Veillard344cee72001-08-20 00:08:40 +00002189 if (pubID == NULL)
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002190 return(NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00002191
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002192 if (!xmlCatalogInitialized)
2193 xmlInitializeCatalog();
2194
2195 /*
2196 * Check first the XML catalogs
2197 */
2198 if (xmlDefaultXMLCatalogList != NULL) {
2199 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2200 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
2201 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
2202 result[sizeof(result) - 1] = 0;
2203 return(result);
2204 }
2205 }
2206
2207 if (xmlDefaultCatalog != NULL)
2208 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
2209 return(NULL);
2210}
2211
2212/**
2213 * xmlCatalogResolvePublic:
2214 * @pubId: the public ID string
2215 *
2216 * Try to lookup the system ID associated to a public ID
2217 *
2218 * Returns the system ID if found or NULL otherwise, the value returned
2219 * must be freed by the caller.
2220 */
2221xmlChar *
2222xmlCatalogResolvePublic(const xmlChar *pubID) {
2223 xmlCatalogEntryPtr catal;
2224 xmlChar *ret;
2225 const xmlChar *sgml;
2226
2227 if (pubID == NULL)
2228 return(NULL);
2229
2230 if (!xmlCatalogInitialized)
2231 xmlInitializeCatalog();
2232
Daniel Veillard344cee72001-08-20 00:08:40 +00002233 /*
2234 * Check first the XML catalogs
2235 */
2236 catal = xmlDefaultXMLCatalogList;
2237 if (catal != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002238 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
2239 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
Daniel Veillard344cee72001-08-20 00:08:40 +00002240 return(ret);
2241 }
2242
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002243 if (xmlDefaultCatalog != NULL) {
2244 sgml = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
2245 if (sgml != NULL)
2246 return(xmlStrdup(sgml));
2247 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002248 return(NULL);
2249}
Daniel Veillard344cee72001-08-20 00:08:40 +00002250
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002251/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002252 * xmlCatalogResolve:
2253 * @pubId: the public ID string
2254 * @sysId: the system ID string
2255 *
2256 * Do a complete resolution lookup of an External Identifier
2257 *
2258 * Returns the URI of the resource or NULL if not found, it must be freed
2259 * by the caller.
2260 */
2261xmlChar *
2262xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002263 if ((pubID == NULL) && (sysID == NULL))
2264 return(NULL);
2265
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002266 if (!xmlCatalogInitialized)
2267 xmlInitializeCatalog();
2268
Daniel Veillard6990bf32001-08-23 21:17:48 +00002269 if (xmlDebugCatalogs)
2270 if (pubID != NULL)
2271 xmlGenericError(xmlGenericErrorContext,
2272 "Resolve: pubID %s\n", pubID);
2273 else
2274 xmlGenericError(xmlGenericErrorContext,
2275 "Resolve: sysID %s\n", sysID);
2276
Daniel Veillardcda96922001-08-21 10:56:31 +00002277 if (xmlDefaultXMLCatalogList != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002278 xmlChar *ret;
2279 ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, sysID);
2280 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2281 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002282 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002283 const xmlChar *ret;
2284
2285 ret = xmlCatalogSGMLResolve(pubID, sysID);
2286 if (ret != NULL)
2287 return(xmlStrdup(ret));
Daniel Veillardcda96922001-08-21 10:56:31 +00002288 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002289 return(NULL);
Daniel Veillardcda96922001-08-21 10:56:31 +00002290}
2291
2292/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002293 * xmlCatalogResolveURI:
2294 * @pubId: the URI
2295 *
2296 * Do a complete resolution lookup of an URI
2297 *
2298 * Returns the URI of the resource or NULL if not found, it must be freed
2299 * by the caller.
2300 */
2301xmlChar *
2302xmlCatalogResolveURI(const xmlChar *URI) {
2303 if (!xmlCatalogInitialized)
2304 xmlInitializeCatalog();
2305
Daniel Veillard6990bf32001-08-23 21:17:48 +00002306 if (URI == NULL)
2307 return(NULL);
2308
2309 if (xmlDebugCatalogs)
2310 xmlGenericError(xmlGenericErrorContext,
2311 "Resolve URI %s\n", URI);
2312
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002313 if (xmlDefaultXMLCatalogList != NULL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002314 xmlChar *ret;
2315
2316 ret = xmlCatalogListXMLResolveURI(xmlDefaultXMLCatalogList, URI);
2317 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2318 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002319 } else {
2320 const xmlChar *ret;
2321
2322 ret = xmlCatalogSGMLResolve(NULL, URI);
2323 if (ret != NULL)
2324 return(xmlStrdup(ret));
2325 }
2326 return(NULL);
2327}
2328
2329/**
Daniel Veillarda7374592001-05-10 14:17:55 +00002330 * xmlCatalogDump:
2331 * @out: the file.
2332 *
2333 * Free up all the memory associated with catalogs
2334 */
2335void
2336xmlCatalogDump(FILE *out) {
2337 if (out == NULL)
2338 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00002339
2340 if (xmlDefaultXMLCatalogList != NULL) {
2341 xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList);
2342 } else if (xmlDefaultCatalog != NULL) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002343 xmlHashScan(xmlDefaultCatalog,
2344 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00002345 }
2346}
2347
2348/**
2349 * xmlCatalogAdd:
2350 * @type: the type of record to add to the catalog
2351 * @orig: the system, public or prefix to match
2352 * @replace: the replacement value for the match
2353 *
2354 * Add an entry in the catalog, it may overwrite existing but
2355 * different entries.
2356 *
2357 * Returns 0 if successful, -1 otherwise
2358 */
2359int
2360xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
2361 int res = -1;
2362
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00002363 if ((xmlDefaultXMLCatalogList == NULL) &&
2364 (xmlStrEqual(type, BAD_CAST "catalog"))) {
2365 xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2366 orig, xmlCatalogDefaultPrefer);
2367 return(0);
2368 }
2369
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002370 if (!xmlCatalogInitialized)
2371 xmlInitializeCatalog();
2372
Daniel Veillard344cee72001-08-20 00:08:40 +00002373 if (xmlDefaultXMLCatalogList != NULL) {
2374 res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
2375 } else if (xmlDefaultCatalog != NULL) {
2376 xmlCatalogEntryType typ;
2377
Daniel Veillardcda96922001-08-21 10:56:31 +00002378 typ = xmlGetSGMLCatalogEntryType(type);
Daniel Veillard344cee72001-08-20 00:08:40 +00002379 if (type != XML_CATA_NONE) {
2380 xmlCatalogEntryPtr entry;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002381 entry = xmlNewCatalogEntry(typ, orig, replace, XML_CATA_PREFER_NONE);
Daniel Veillard344cee72001-08-20 00:08:40 +00002382 res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
2383 }
2384 }
2385 return(res);
2386}
2387
2388/**
2389 * xmlCatalogRemove:
2390 * @value: the value to remove
2391 *
2392 * Remove an entry from the catalog
2393 *
2394 * Returns 0 if successful, -1 otherwise
2395 */
2396int
2397xmlCatalogRemove(const xmlChar *value) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002398 int res = -1;
2399
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002400 if (!xmlCatalogInitialized)
2401 xmlInitializeCatalog();
2402
Daniel Veillardcda96922001-08-21 10:56:31 +00002403 if (xmlDefaultXMLCatalogList != NULL) {
2404 res = xmlDelXMLCatalog(xmlDefaultXMLCatalogList, value);
2405 } else if (xmlDefaultCatalog != NULL) {
2406 TODO
2407 }
2408 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00002409}
2410
2411/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002412 * xmlCatalogGetDefaults:
2413 *
2414 * Used to get the user preference w.r.t. to what catalogs should
2415 * be accepted
2416 *
2417 * Returns the current xmlCatalogAllow value
2418 */
2419xmlCatalogAllow
2420xmlCatalogGetDefaults(void) {
2421 return(xmlCatalogDefaultAllow);
2422}
2423
2424/**
2425 * xmlCatalogSetDefaults:
2426 *
2427 * Used to set the user preference w.r.t. to what catalogs should
2428 * be accepted
2429 */
2430void
2431xmlCatalogSetDefaults(xmlCatalogAllow allow) {
2432 if (!xmlCatalogInitialized)
2433 xmlInitializeCatalog();
2434 if (xmlDebugCatalogs) {
2435 switch (allow) {
2436 case XML_CATA_ALLOW_NONE:
2437 xmlGenericError(xmlGenericErrorContext,
2438 "Disabling catalog usage\n");
2439 break;
2440 case XML_CATA_ALLOW_GLOBAL:
2441 xmlGenericError(xmlGenericErrorContext,
2442 "Allowing only global catalogs\n");
2443 break;
2444 case XML_CATA_ALLOW_DOCUMENT:
2445 xmlGenericError(xmlGenericErrorContext,
2446 "Allowing only catalogs from the document\n");
2447 break;
2448 case XML_CATA_ALLOW_ALL:
2449 xmlGenericError(xmlGenericErrorContext,
2450 "Allowing all catalogs\n");
2451 break;
2452 }
2453 }
2454 xmlCatalogDefaultAllow = allow;
2455}
2456
2457/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002458 * xmlCatalogSetDefaultPrefer:
2459 * @prefer: the default preference for delegation
2460 *
2461 * Allows to set the preference between public and system for deletion
2462 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002463 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002464 *
2465 * Returns the previous value of the default preference for delegation
2466 */
2467xmlCatalogPrefer
2468xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
2469 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
2470
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002471 if (!xmlCatalogInitialized)
2472 xmlInitializeCatalog();
2473 if (prefer == XML_CATA_PREFER_NONE)
2474 return(ret);
2475
2476 if (xmlDebugCatalogs) {
2477 switch (prefer) {
2478 case XML_CATA_PREFER_PUBLIC:
2479 xmlGenericError(xmlGenericErrorContext,
2480 "Setting catalog preference to PUBLIC\n");
2481 break;
2482 case XML_CATA_PREFER_SYSTEM:
2483 xmlGenericError(xmlGenericErrorContext,
2484 "Setting catalog preference to SYSTEM\n");
2485 break;
2486 case XML_CATA_PREFER_NONE:
2487 break;
2488 }
2489 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002490 xmlCatalogDefaultPrefer = prefer;
2491 return(ret);
2492}
2493
2494/**
Daniel Veillard344cee72001-08-20 00:08:40 +00002495 * xmlCatalogSetDebug:
2496 * @level: the debug level of catalogs required
2497 *
2498 * Used to set the debug level for catalog operation, 0 disable
2499 * debugging, 1 enable it
2500 *
2501 * Returns the previous value of the catalog debugging level
2502 */
2503int
2504xmlCatalogSetDebug(int level) {
2505 int ret = xmlDebugCatalogs;
2506
2507 if (level <= 0)
2508 xmlDebugCatalogs = 0;
2509 else
2510 xmlDebugCatalogs = level;
2511 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00002512}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002513
2514/**
2515 * xmlCatalogFreeLocal:
2516 * @catalogs: a document's list of catalogs
2517 *
2518 * Free up the memory associated to the catalog list
2519 */
2520void
2521xmlCatalogFreeLocal(void *catalogs) {
2522 xmlCatalogEntryPtr catal;
2523
2524 catal = (xmlCatalogEntryPtr) catalogs;
2525 if (catal != NULL)
2526 xmlFreeCatalogEntryList(catal);
2527}
2528
2529
2530/**
2531 * xmlCatalogAddLocal:
2532 * @catalogs: a document's list of catalogs
2533 * @URL: the URL to a new local catalog
2534 *
2535 * Add the new entry to the catalog list
2536 *
2537 * Returns the updated list
2538 */
2539void *
2540xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
2541 xmlCatalogEntryPtr catal, add;
2542
2543 if (!xmlCatalogInitialized)
2544 xmlInitializeCatalog();
2545 if (URL == NULL)
2546 return(catalogs);
2547
2548 if (xmlDebugCatalogs)
2549 xmlGenericError(xmlGenericErrorContext,
2550 "Adding document catalog %s\n", URL);
2551
2552 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
2553 xmlCatalogDefaultPrefer);
2554 if (add == NULL)
2555 return(catalogs);
2556
2557 catal = (xmlCatalogEntryPtr) catalogs;
2558 if (catal == NULL)
2559 return((void *) add);
2560
2561 while (catal->next != NULL)
2562 catal = catal->next;
2563 catal->next = add;
2564 return(catalogs);
2565}
2566
2567/**
2568 * xmlCatalogLocalResolve:
2569 * @catalogs: a document's list of catalogs
2570 * @pubId: the public ID string
2571 * @sysId: the system ID string
2572 *
2573 * Do a complete resolution lookup of an External Identifier using a
2574 * document's private catalog list
2575 *
2576 * Returns the URI of the resource or NULL if not found, it must be freed
2577 * by the caller.
2578 */
2579xmlChar *
2580xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
2581 const xmlChar *sysID) {
2582 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002583 xmlChar *ret;
2584
2585 if ((pubID == NULL) && (sysID == NULL))
2586 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002587
2588 if (!xmlCatalogInitialized)
2589 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00002590
2591 if (xmlDebugCatalogs)
2592 if (pubID != NULL)
2593 xmlGenericError(xmlGenericErrorContext,
2594 "Local resolve: pubID %s\n", pubID);
2595 else
2596 xmlGenericError(xmlGenericErrorContext,
2597 "Local resolve: sysID %s\n", sysID);
2598
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002599 catal = (xmlCatalogEntryPtr) catalogs;
2600 if (catal == NULL)
2601 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002602 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
2603 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2604 return(ret);
2605 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002606}
2607
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002608/**
2609 * xmlCatalogLocalResolveURI:
2610 * @catalogs: a document's list of catalogs
2611 * @pubId: the URI
2612 *
2613 * Do a complete resolution lookup of an URI using a
2614 * document's private catalog list
2615 *
2616 * Returns the URI of the resource or NULL if not found, it must be freed
2617 * by the caller.
2618 */
2619xmlChar *
2620xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
2621 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00002622 xmlChar *ret;
2623
2624 if (URI == NULL)
2625 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002626
2627 if (!xmlCatalogInitialized)
2628 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00002629
2630 if (xmlDebugCatalogs)
2631 xmlGenericError(xmlGenericErrorContext,
2632 "Resolve URI %s\n", URI);
2633
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002634 catal = (xmlCatalogEntryPtr) catalogs;
2635 if (catal == NULL)
2636 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002637 ret = xmlCatalogListXMLResolveURI(catal, URI);
2638 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
2639 return(ret);
2640 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002641}
2642
Daniel Veillarda7374592001-05-10 14:17:55 +00002643#endif /* LIBXML_CATALOG_ENABLED */