blob: f6186a1c844e98f718c8fc5b0bf185b834d2940c [file] [log] [blame]
Daniel Veillarda7374592001-05-10 14:17:55 +00001/**
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002 * catalog.c: set of generic Catalog related routines
Daniel Veillarda7374592001-05-10 14:17:55 +00003 *
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
Daniel Veillard34ce8be2002-03-18 19:37:11 +000015#define IN_LIBXML
Daniel Veillarda7374592001-05-10 14:17:55 +000016#include "libxml.h"
17
18#ifdef LIBXML_CATALOG_ENABLED
19#ifdef HAVE_SYS_TYPES_H
20#include <sys/types.h>
21#endif
22#ifdef HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28#ifdef HAVE_FCNTL_H
29#include <fcntl.h>
30#endif
Daniel Veillardc0631a62001-09-20 13:56:06 +000031#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
Daniel Veillarda7374592001-05-10 14:17:55 +000034#include <string.h>
35#include <libxml/xmlmemory.h>
36#include <libxml/hash.h>
37#include <libxml/uri.h>
38#include <libxml/parserInternals.h>
39#include <libxml/catalog.h>
40#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000041#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000042#include <libxml/globals.h>
Daniel Veillarda7374592001-05-10 14:17:55 +000043
Daniel Veillard2a1d2422012-07-16 14:38:14 +080044#include "buf.h"
45
Daniel Veillard6990bf32001-08-23 21:17:48 +000046#define MAX_DELEGATE 50
Daniel Veillard5ee43b02003-08-04 00:58:46 +000047#define MAX_CATAL_DEPTH 50
Daniel Veillard6990bf32001-08-23 21:17:48 +000048
Daniel Veillarded121382007-04-17 12:33:19 +000049#ifdef _WIN32
Jan Pokorný9811ce72016-04-13 16:56:06 +020050# define PATH_SEPARATOR ';'
Daniel Veillarded121382007-04-17 12:33:19 +000051#else
Jan Pokorný9811ce72016-04-13 16:56:06 +020052# define PATH_SEPARATOR ':'
Daniel Veillarded121382007-04-17 12:33:19 +000053#endif
54
Daniel Veillard344cee72001-08-20 00:08:40 +000055/**
56 * TODO:
57 *
58 * macro to flag unimplemented blocks
Daniel Veillard3e59fc52003-04-18 12:34:58 +000059 * XML_CATALOG_PREFER user env to select between system/public prefered
60 * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
61 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
62 *> values "system" and "public". I have made the default be "system" to
63 *> match yours.
Daniel Veillard344cee72001-08-20 00:08:40 +000064 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +080065#define TODO \
Daniel Veillard344cee72001-08-20 00:08:40 +000066 xmlGenericError(xmlGenericErrorContext, \
67 "Unimplemented block at %s:%d\n", \
68 __FILE__, __LINE__);
69
Daniel Veillardcda96922001-08-21 10:56:31 +000070#define XML_URN_PUBID "urn:publicid:"
Daniel Veillarde2940dd2001-08-22 00:06:49 +000071#define XML_CATAL_BREAK ((xmlChar *) -1)
Daniel Veillard75b96822001-10-11 18:59:45 +000072#ifndef XML_XML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000073#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000074#endif
Daniel Veillard75b96822001-10-11 18:59:45 +000075#ifndef XML_SGML_DEFAULT_CATALOG
Daniel Veillardf7b094f2001-11-15 13:54:39 +000076#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
Daniel Veillard75b96822001-10-11 18:59:45 +000077#endif
78
Daniel Veillardfb382b82004-06-14 12:13:12 +000079#if defined(_WIN32) && defined(_MSC_VER)
80#undef XML_XML_DEFAULT_CATALOG
81static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
Daniel Veillard59d3ed82007-04-17 12:44:58 +000082#if defined(_WIN32_WCE)
83/* Windows CE don't have a A variant */
84#define GetModuleHandleA GetModuleHandle
85#define GetModuleFileNameA GetModuleFileName
86#else
Denis Pauke1631e12013-03-10 12:47:37 +020087#if !defined(_WINDOWS_)
Daniel Veillardfb382b82004-06-14 12:13:12 +000088void* __stdcall GetModuleHandleA(const char*);
89unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
90#endif
Daniel Veillard59d3ed82007-04-17 12:44:58 +000091#endif
Denis Pauke1631e12013-03-10 12:47:37 +020092#endif
Daniel Veillardfb382b82004-06-14 12:13:12 +000093
Daniel Veillardc8155052004-07-16 09:03:08 +000094static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
Daniel Veillard85c11fa2001-10-16 21:03:08 +000095static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +000096
Daniel Veillarda7374592001-05-10 14:17:55 +000097/************************************************************************
98 * *
99 * Types, all private *
100 * *
101 ************************************************************************/
102
103typedef enum {
Daniel Veillardc853b322001-11-06 15:24:37 +0000104 XML_CATA_REMOVED = -1,
Daniel Veillarda7374592001-05-10 14:17:55 +0000105 XML_CATA_NONE = 0,
Daniel Veillarda7374592001-05-10 14:17:55 +0000106 XML_CATA_CATALOG,
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000107 XML_CATA_BROKEN_CATALOG,
Daniel Veillard344cee72001-08-20 00:08:40 +0000108 XML_CATA_NEXT_CATALOG,
William M. Brackb7b54de2004-10-06 16:38:01 +0000109 XML_CATA_GROUP,
Daniel Veillard344cee72001-08-20 00:08:40 +0000110 XML_CATA_PUBLIC,
111 XML_CATA_SYSTEM,
112 XML_CATA_REWRITE_SYSTEM,
113 XML_CATA_DELEGATE_PUBLIC,
114 XML_CATA_DELEGATE_SYSTEM,
115 XML_CATA_URI,
116 XML_CATA_REWRITE_URI,
117 XML_CATA_DELEGATE_URI,
118 SGML_CATA_SYSTEM,
119 SGML_CATA_PUBLIC,
120 SGML_CATA_ENTITY,
121 SGML_CATA_PENTITY,
122 SGML_CATA_DOCTYPE,
123 SGML_CATA_LINKTYPE,
124 SGML_CATA_NOTATION,
125 SGML_CATA_DELEGATE,
126 SGML_CATA_BASE,
127 SGML_CATA_CATALOG,
128 SGML_CATA_DOCUMENT,
129 SGML_CATA_SGMLDECL
Daniel Veillarda7374592001-05-10 14:17:55 +0000130} xmlCatalogEntryType;
131
132typedef struct _xmlCatalogEntry xmlCatalogEntry;
133typedef xmlCatalogEntry *xmlCatalogEntryPtr;
134struct _xmlCatalogEntry {
Daniel Veillard344cee72001-08-20 00:08:40 +0000135 struct _xmlCatalogEntry *next;
136 struct _xmlCatalogEntry *parent;
137 struct _xmlCatalogEntry *children;
Daniel Veillarda7374592001-05-10 14:17:55 +0000138 xmlCatalogEntryType type;
139 xmlChar *name;
140 xmlChar *value;
Daniel Veillardc853b322001-11-06 15:24:37 +0000141 xmlChar *URL; /* The expanded URL using the base */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000142 xmlCatalogPrefer prefer;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000143 int dealloc;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000144 int depth;
William M. Brackb7b54de2004-10-06 16:38:01 +0000145 struct _xmlCatalogEntry *group;
Daniel Veillarda7374592001-05-10 14:17:55 +0000146};
147
Daniel Veillard75b96822001-10-11 18:59:45 +0000148typedef enum {
149 XML_XML_CATALOG_TYPE = 1,
150 XML_SGML_CATALOG_TYPE
151} xmlCatalogType;
152
153#define XML_MAX_SGML_CATA_DEPTH 10
154struct _xmlCatalog {
155 xmlCatalogType type; /* either XML or SGML */
156
157 /*
158 * SGML Catalogs are stored as a simple hash table of catalog entries
159 * Catalog stack to check against overflows when building the
160 * SGML catalog
161 */
162 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
163 int catalNr; /* Number of current catal streams */
164 int catalMax; /* Max number of catal streams */
165 xmlHashTablePtr sgml;
166
167 /*
168 * XML Catalogs are stored as a tree of Catalog entries
169 */
170 xmlCatalogPrefer prefer;
171 xmlCatalogEntryPtr xml;
172};
173
174/************************************************************************
175 * *
176 * Global variables *
177 * *
178 ************************************************************************/
179
Daniel Veillard81463942001-10-16 12:34:39 +0000180/*
181 * Those are preferences
182 */
183static int xmlDebugCatalogs = 0; /* used for debugging */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +0000184static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000185static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
Daniel Veillard75b96822001-10-11 18:59:45 +0000186
187/*
188 * Hash table containing all the trees of XML catalogs parsed by
189 * the application.
190 */
Daniel Veillard6990bf32001-08-23 21:17:48 +0000191static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000192
193/*
194 * The default catalog in use by the application
195 */
196static xmlCatalogPtr xmlDefaultCatalog = NULL;
197
198/*
Daniel Veillard81463942001-10-16 12:34:39 +0000199 * A mutex for modifying the shared global catalog(s)
200 * xmlDefaultCatalog tree.
201 * It also protects xmlCatalogXMLFiles
202 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
203 */
204static xmlRMutexPtr xmlCatalogMutex = NULL;
205
206/*
Daniel Veillard75b96822001-10-11 18:59:45 +0000207 * Whether the catalog support was initialized.
208 */
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000209static int xmlCatalogInitialized = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000210
Daniel Veillard69d2c172003-10-09 11:46:07 +0000211/************************************************************************
212 * *
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800213 * Catalog error handlers *
Daniel Veillard69d2c172003-10-09 11:46:07 +0000214 * *
215 ************************************************************************/
216
217/**
218 * xmlCatalogErrMemory:
219 * @extra: extra informations
220 *
221 * Handle an out of memory condition
222 */
223static void
224xmlCatalogErrMemory(const char *extra)
225{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000226 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000227 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
228 extra, NULL, NULL, 0, 0,
229 "Memory allocation failed : %s\n", extra);
230}
231
232/**
233 * xmlCatalogErr:
234 * @catal: the Catalog entry
235 * @node: the context node
236 * @msg: the error message
237 * @extra: extra informations
238 *
239 * Handle a catalog error
240 */
David Kilzer4472c3a2016-05-13 15:13:17 +0800241static void LIBXML_ATTR_FORMAT(4,0)
Daniel Veillard69d2c172003-10-09 11:46:07 +0000242xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
243 const char *msg, const xmlChar *str1, const xmlChar *str2,
244 const xmlChar *str3)
245{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000246 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
Daniel Veillard69d2c172003-10-09 11:46:07 +0000247 error, XML_ERR_ERROR, NULL, 0,
248 (const char *) str1, (const char *) str2,
249 (const char *) str3, 0, 0,
250 msg, str1, str2, str3);
251}
252
Daniel Veillarda7374592001-05-10 14:17:55 +0000253
254/************************************************************************
255 * *
Daniel Veillard75b96822001-10-11 18:59:45 +0000256 * Allocation and Freeing *
Daniel Veillarda7374592001-05-10 14:17:55 +0000257 * *
258 ************************************************************************/
259
Daniel Veillard75b96822001-10-11 18:59:45 +0000260/**
261 * xmlNewCatalogEntry:
262 * @type: type of entry
263 * @name: name of the entry
264 * @value: value of the entry
265 * @prefer: the PUBLIC vs. SYSTEM current preference value
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800266 * @group: for members of a group, the group entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000267 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800268 * create a new Catalog entry, this type is shared both by XML and
Daniel Veillard75b96822001-10-11 18:59:45 +0000269 * SGML catalogs, but the acceptable types values differs.
270 *
271 * Returns the xmlCatalogEntryPtr or NULL in case of error
272 */
Daniel Veillarda7374592001-05-10 14:17:55 +0000273static xmlCatalogEntryPtr
Daniel Veillard344cee72001-08-20 00:08:40 +0000274xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
William M. Brackb7b54de2004-10-06 16:38:01 +0000275 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
276 xmlCatalogEntryPtr group) {
Daniel Veillarda7374592001-05-10 14:17:55 +0000277 xmlCatalogEntryPtr ret;
Daniel Veillardc8155052004-07-16 09:03:08 +0000278 xmlChar *normid = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000279
280 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
281 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000282 xmlCatalogErrMemory("allocating catalog entry");
Daniel Veillarda7374592001-05-10 14:17:55 +0000283 return(NULL);
284 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000285 ret->next = NULL;
286 ret->parent = NULL;
287 ret->children = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +0000288 ret->type = type;
Daniel Veillardc8155052004-07-16 09:03:08 +0000289 if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
290 normid = xmlCatalogNormalizePublic(name);
291 if (normid != NULL)
292 name = (*normid != 0 ? normid : NULL);
293 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000294 if (name != NULL)
295 ret->name = xmlStrdup(name);
296 else
297 ret->name = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +0000298 if (normid != NULL)
299 xmlFree(normid);
Daniel Veillard344cee72001-08-20 00:08:40 +0000300 if (value != NULL)
301 ret->value = xmlStrdup(value);
302 else
303 ret->value = NULL;
Daniel Veillardc853b322001-11-06 15:24:37 +0000304 if (URL == NULL)
305 URL = value;
306 if (URL != NULL)
307 ret->URL = xmlStrdup(URL);
308 else
309 ret->URL = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000310 ret->prefer = prefer;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000311 ret->dealloc = 0;
Daniel Veillard5ee43b02003-08-04 00:58:46 +0000312 ret->depth = 0;
William M. Brackb7b54de2004-10-06 16:38:01 +0000313 ret->group = group;
Daniel Veillarda7374592001-05-10 14:17:55 +0000314 return(ret);
315}
316
317static void
Daniel Veillard344cee72001-08-20 00:08:40 +0000318xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
319
Daniel Veillard75b96822001-10-11 18:59:45 +0000320/**
321 * xmlFreeCatalogEntry:
322 * @ret: a Catalog entry
323 *
324 * Free the memory allocated to a Catalog entry
325 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000326static void
Daniel Veillarda7374592001-05-10 14:17:55 +0000327xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
328 if (ret == NULL)
329 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000330 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000331 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000332 * only by the file hash cleaner !
333 */
334 if (ret->dealloc == 1)
335 return;
336
337 if (xmlDebugCatalogs) {
338 if (ret->name != NULL)
339 xmlGenericError(xmlGenericErrorContext,
340 "Free catalog entry %s\n", ret->name);
341 else if (ret->value != NULL)
342 xmlGenericError(xmlGenericErrorContext,
343 "Free catalog entry %s\n", ret->value);
344 else
345 xmlGenericError(xmlGenericErrorContext,
346 "Free catalog entry\n");
347 }
348
Daniel Veillarda7374592001-05-10 14:17:55 +0000349 if (ret->name != NULL)
350 xmlFree(ret->name);
351 if (ret->value != NULL)
352 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000353 if (ret->URL != NULL)
354 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000355 xmlFree(ret);
356}
357
Daniel Veillard75b96822001-10-11 18:59:45 +0000358/**
359 * xmlFreeCatalogEntryList:
360 * @ret: a Catalog entry list
361 *
362 * Free the memory allocated to a full chained list of Catalog entries
363 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000364static void
365xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
366 xmlCatalogEntryPtr next;
367
368 while (ret != NULL) {
369 next = ret->next;
370 xmlFreeCatalogEntry(ret);
371 ret = next;
372 }
373}
374
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000375/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000376 * xmlFreeCatalogHashEntryList:
377 * @ret: a Catalog entry list
378 *
379 * Free the memory allocated to list of Catalog entries from the
380 * catalog file hash.
381 */
382static void
383xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
384 xmlCatalogEntryPtr children, next;
385
386 if (catal == NULL)
387 return;
388
389 children = catal->children;
390 while (children != NULL) {
391 next = children->next;
392 children->dealloc = 0;
393 children->children = NULL;
394 xmlFreeCatalogEntry(children);
395 children = next;
396 }
397 catal->dealloc = 0;
398 xmlFreeCatalogEntry(catal);
399}
400
401/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000402 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000403 * @type: type of catalog
404 * @prefer: the PUBLIC vs. SYSTEM current preference value
405 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800406 * create a new Catalog, this type is shared both by XML and
Daniel Veillard75b96822001-10-11 18:59:45 +0000407 * SGML catalogs, but the acceptable types values differs.
408 *
409 * Returns the xmlCatalogPtr or NULL in case of error
410 */
411static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000412xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000413 xmlCatalogPtr ret;
414
415 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
416 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000417 xmlCatalogErrMemory("allocating catalog");
Daniel Veillard75b96822001-10-11 18:59:45 +0000418 return(NULL);
419 }
420 memset(ret, 0, sizeof(xmlCatalog));
421 ret->type = type;
422 ret->catalNr = 0;
423 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
424 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000425 if (ret->type == XML_SGML_CATALOG_TYPE)
426 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000427 return(ret);
428}
429
430/**
431 * xmlFreeCatalog:
Daniel Veillard06d25242004-02-25 13:01:42 +0000432 * @catal: a Catalog
Daniel Veillard75b96822001-10-11 18:59:45 +0000433 *
434 * Free the memory allocated to a Catalog
435 */
436void
437xmlFreeCatalog(xmlCatalogPtr catal) {
438 if (catal == NULL)
439 return;
440 if (catal->xml != NULL)
441 xmlFreeCatalogEntryList(catal->xml);
442 if (catal->sgml != NULL)
443 xmlHashFree(catal->sgml,
444 (xmlHashDeallocator) xmlFreeCatalogEntry);
445 xmlFree(catal);
446}
447
448/************************************************************************
449 * *
450 * Serializing Catalogs *
451 * *
452 ************************************************************************/
453
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000454#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +0000455/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000456 * xmlCatalogDumpEntry:
Daniel Veillard06d25242004-02-25 13:01:42 +0000457 * @entry: the catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000458 * @out: the file.
459 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000460 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000461 */
462static void
463xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
464 if ((entry == NULL) || (out == NULL))
465 return;
466 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000467 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000468 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000469 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000470 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000471 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000472 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000473 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000474 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000475 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000476 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000477 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000478 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000479 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000480 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000481 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000482 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000483 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000484 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000485 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000486 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000487 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000488 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000489 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000490 fprintf(out, "SGMLDECL "); break;
491 default:
492 return;
493 }
494 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000495 case SGML_CATA_ENTITY:
496 case SGML_CATA_PENTITY:
497 case SGML_CATA_DOCTYPE:
498 case SGML_CATA_LINKTYPE:
499 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000500 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000501 case SGML_CATA_PUBLIC:
502 case SGML_CATA_SYSTEM:
503 case SGML_CATA_SGMLDECL:
504 case SGML_CATA_DOCUMENT:
505 case SGML_CATA_CATALOG:
506 case SGML_CATA_BASE:
507 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000508 fprintf(out, "\"%s\"", entry->name); break;
509 default:
510 break;
511 }
512 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000513 case SGML_CATA_ENTITY:
514 case SGML_CATA_PENTITY:
515 case SGML_CATA_DOCTYPE:
516 case SGML_CATA_LINKTYPE:
517 case SGML_CATA_NOTATION:
518 case SGML_CATA_PUBLIC:
519 case SGML_CATA_SYSTEM:
520 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000521 fprintf(out, " \"%s\"", entry->value); break;
522 default:
523 break;
524 }
525 fprintf(out, "\n");
526}
527
William M. Brackb7b54de2004-10-06 16:38:01 +0000528/**
529 * xmlDumpXMLCatalogNode:
530 * @catal: top catalog entry
531 * @catalog: pointer to the xml tree
532 * @doc: the containing document
533 * @ns: the current namespace
534 * @cgroup: group node for group members
535 *
536 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
537 * for group entries
538 */
539static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
540 xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
541 xmlNodePtr node;
542 xmlCatalogEntryPtr cur;
543 /*
544 * add all the catalog entries
545 */
546 cur = catal;
547 while (cur != NULL) {
548 if (cur->group == cgroup) {
549 switch (cur->type) {
550 case XML_CATA_REMOVED:
551 break;
552 case XML_CATA_BROKEN_CATALOG:
553 case XML_CATA_CATALOG:
554 if (cur == catal) {
555 cur = cur->children;
556 continue;
557 }
558 break;
559 case XML_CATA_NEXT_CATALOG:
560 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
561 xmlSetProp(node, BAD_CAST "catalog", cur->value);
562 xmlAddChild(catalog, node);
563 break;
564 case XML_CATA_NONE:
565 break;
566 case XML_CATA_GROUP:
567 node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
568 xmlSetProp(node, BAD_CAST "id", cur->name);
William M. Brack6218b312004-10-06 17:52:32 +0000569 if (cur->value != NULL) {
570 xmlNsPtr xns;
571 xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
572 if (xns != NULL)
573 xmlSetNsProp(node, xns, BAD_CAST "base",
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800574 cur->value);
William M. Brack6218b312004-10-06 17:52:32 +0000575 }
William M. Brackb7b54de2004-10-06 16:38:01 +0000576 switch (cur->prefer) {
577 case XML_CATA_PREFER_NONE:
578 break;
579 case XML_CATA_PREFER_PUBLIC:
580 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
581 break;
582 case XML_CATA_PREFER_SYSTEM:
583 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
584 break;
585 }
586 xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
587 xmlAddChild(catalog, node);
588 break;
589 case XML_CATA_PUBLIC:
590 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
591 xmlSetProp(node, BAD_CAST "publicId", cur->name);
592 xmlSetProp(node, BAD_CAST "uri", cur->value);
593 xmlAddChild(catalog, node);
594 break;
595 case XML_CATA_SYSTEM:
596 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
597 xmlSetProp(node, BAD_CAST "systemId", cur->name);
598 xmlSetProp(node, BAD_CAST "uri", cur->value);
599 xmlAddChild(catalog, node);
600 break;
601 case XML_CATA_REWRITE_SYSTEM:
602 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
603 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
604 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
605 xmlAddChild(catalog, node);
606 break;
607 case XML_CATA_DELEGATE_PUBLIC:
608 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
609 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
610 xmlSetProp(node, BAD_CAST "catalog", cur->value);
611 xmlAddChild(catalog, node);
612 break;
613 case XML_CATA_DELEGATE_SYSTEM:
614 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
615 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
616 xmlSetProp(node, BAD_CAST "catalog", cur->value);
617 xmlAddChild(catalog, node);
618 break;
619 case XML_CATA_URI:
620 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
621 xmlSetProp(node, BAD_CAST "name", cur->name);
622 xmlSetProp(node, BAD_CAST "uri", cur->value);
623 xmlAddChild(catalog, node);
624 break;
625 case XML_CATA_REWRITE_URI:
626 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
627 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
628 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
629 xmlAddChild(catalog, node);
630 break;
631 case XML_CATA_DELEGATE_URI:
632 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
633 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
634 xmlSetProp(node, BAD_CAST "catalog", cur->value);
635 xmlAddChild(catalog, node);
636 break;
637 case SGML_CATA_SYSTEM:
638 case SGML_CATA_PUBLIC:
639 case SGML_CATA_ENTITY:
640 case SGML_CATA_PENTITY:
641 case SGML_CATA_DOCTYPE:
642 case SGML_CATA_LINKTYPE:
643 case SGML_CATA_NOTATION:
644 case SGML_CATA_DELEGATE:
645 case SGML_CATA_BASE:
646 case SGML_CATA_CATALOG:
647 case SGML_CATA_DOCUMENT:
648 case SGML_CATA_SGMLDECL:
649 break;
650 }
651 }
652 cur = cur->next;
653 }
654}
655
Daniel Veillard75b96822001-10-11 18:59:45 +0000656static int
657xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
658 int ret;
659 xmlDocPtr doc;
660 xmlNsPtr ns;
661 xmlDtdPtr dtd;
William M. Brackb7b54de2004-10-06 16:38:01 +0000662 xmlNodePtr catalog;
Daniel Veillard75b96822001-10-11 18:59:45 +0000663 xmlOutputBufferPtr buf;
Daniel Veillard75b96822001-10-11 18:59:45 +0000664
665 /*
666 * Rebuild a catalog
667 */
668 doc = xmlNewDoc(NULL);
669 if (doc == NULL)
670 return(-1);
671 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
672 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
673BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
674
675 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
676
677 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
678 if (ns == NULL) {
679 xmlFreeDoc(doc);
680 return(-1);
681 }
682 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
683 if (catalog == NULL) {
684 xmlFreeNs(ns);
685 xmlFreeDoc(doc);
686 return(-1);
687 }
688 catalog->nsDef = ns;
689 xmlAddChild((xmlNodePtr) doc, catalog);
690
William M. Brackb7b54de2004-10-06 16:38:01 +0000691 xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800692
Daniel Veillard75b96822001-10-11 18:59:45 +0000693 /*
694 * reserialize it
695 */
696 buf = xmlOutputBufferCreateFile(out, NULL);
697 if (buf == NULL) {
698 xmlFreeDoc(doc);
699 return(-1);
700 }
701 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
702
703 /*
704 * Free it
705 */
706 xmlFreeDoc(doc);
707
708 return(ret);
709}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000710#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +0000711
712/************************************************************************
713 * *
714 * Converting SGML Catalogs to XML *
715 * *
716 ************************************************************************/
717
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000718/**
719 * xmlCatalogConvertEntry:
720 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000721 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000722 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000723 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000724 */
725static void
Daniel Veillard75b96822001-10-11 18:59:45 +0000726xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
727 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
728 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000729 return;
730 switch (entry->type) {
731 case SGML_CATA_ENTITY:
732 entry->type = XML_CATA_PUBLIC;
733 break;
734 case SGML_CATA_PENTITY:
735 entry->type = XML_CATA_PUBLIC;
736 break;
737 case SGML_CATA_DOCTYPE:
738 entry->type = XML_CATA_PUBLIC;
739 break;
740 case SGML_CATA_LINKTYPE:
741 entry->type = XML_CATA_PUBLIC;
742 break;
743 case SGML_CATA_NOTATION:
744 entry->type = XML_CATA_PUBLIC;
745 break;
746 case SGML_CATA_PUBLIC:
747 entry->type = XML_CATA_PUBLIC;
748 break;
749 case SGML_CATA_SYSTEM:
750 entry->type = XML_CATA_SYSTEM;
751 break;
752 case SGML_CATA_DELEGATE:
753 entry->type = XML_CATA_DELEGATE_PUBLIC;
754 break;
755 case SGML_CATA_CATALOG:
756 entry->type = XML_CATA_CATALOG;
757 break;
758 default:
Daniel Veillard75b96822001-10-11 18:59:45 +0000759 xmlHashRemoveEntry(catal->sgml, entry->name,
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000760 (xmlHashDeallocator) xmlFreeCatalogEntry);
761 return;
762 }
763 /*
764 * Conversion successful, remove from the SGML catalog
765 * and add it to the default XML one
766 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000767 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
768 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000769 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000770 if (catal->xml->children == NULL)
771 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000772 else {
773 xmlCatalogEntryPtr prev;
774
Daniel Veillard75b96822001-10-11 18:59:45 +0000775 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000776 while (prev->next != NULL)
777 prev = prev->next;
778 prev->next = entry;
779 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000780}
781
782/**
783 * xmlConvertSGMLCatalog:
784 * @catal: the catalog
785 *
786 * Convert all the SGML catalog entries as XML ones
787 *
788 * Returns the number of entries converted if successful, -1 otherwise
789 */
790int
791xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
792
793 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
794 return(-1);
795
796 if (xmlDebugCatalogs) {
797 xmlGenericError(xmlGenericErrorContext,
798 "Converting SGML catalog to XML\n");
799 }
800 xmlHashScan(catal->sgml,
801 (xmlHashScanner) xmlCatalogConvertEntry,
802 &catal);
803 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000804}
805
Daniel Veillarda7374592001-05-10 14:17:55 +0000806/************************************************************************
807 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000808 * Helper function *
809 * *
810 ************************************************************************/
811
812/**
813 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000814 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000815 *
816 * Expand the URN into the equivalent Public Identifier
817 *
818 * Returns the new identifier or NULL, the string must be deallocated
819 * by the caller.
820 */
821static xmlChar *
822xmlCatalogUnWrapURN(const xmlChar *urn) {
823 xmlChar result[2000];
824 unsigned int i = 0;
825
826 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
827 return(NULL);
828 urn += sizeof(XML_URN_PUBID) - 1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800829
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000830 while (*urn != 0) {
Daniel Veillard770075b2004-02-25 10:44:30 +0000831 if (i > sizeof(result) - 4)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000832 break;
833 if (*urn == '+') {
834 result[i++] = ' ';
835 urn++;
836 } else if (*urn == ':') {
837 result[i++] = '/';
838 result[i++] = '/';
839 urn++;
840 } else if (*urn == ';') {
841 result[i++] = ':';
842 result[i++] = ':';
843 urn++;
844 } else if (*urn == '%') {
Daniel Veillard770075b2004-02-25 10:44:30 +0000845 if ((urn[1] == '2') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000846 result[i++] = '+';
Daniel Veillard770075b2004-02-25 10:44:30 +0000847 else if ((urn[1] == '3') && (urn[2] == 'A'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000848 result[i++] = ':';
Daniel Veillard770075b2004-02-25 10:44:30 +0000849 else if ((urn[1] == '2') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000850 result[i++] = '/';
Daniel Veillard770075b2004-02-25 10:44:30 +0000851 else if ((urn[1] == '3') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000852 result[i++] = ';';
Daniel Veillard770075b2004-02-25 10:44:30 +0000853 else if ((urn[1] == '2') && (urn[2] == '7'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000854 result[i++] = '\'';
Daniel Veillard770075b2004-02-25 10:44:30 +0000855 else if ((urn[1] == '3') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000856 result[i++] = '?';
Daniel Veillard770075b2004-02-25 10:44:30 +0000857 else if ((urn[1] == '2') && (urn[2] == '3'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000858 result[i++] = '#';
Daniel Veillard770075b2004-02-25 10:44:30 +0000859 else if ((urn[1] == '2') && (urn[2] == '5'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000860 result[i++] = '%';
861 else {
862 result[i++] = *urn;
863 urn++;
864 continue;
865 }
866 urn += 3;
867 } else {
868 result[i++] = *urn;
869 urn++;
870 }
871 }
872 result[i] = 0;
873
874 return(xmlStrdup(result));
875}
876
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000877/**
878 * xmlParseCatalogFile:
879 * @filename: the filename
880 *
881 * parse an XML file and build a tree. It's like xmlParseFile()
882 * except it bypass all catalog lookups.
883 *
884 * Returns the resulting document tree or NULL in case of error
885 */
886
887xmlDocPtr
888xmlParseCatalogFile(const char *filename) {
889 xmlDocPtr ret;
890 xmlParserCtxtPtr ctxt;
891 char *directory = NULL;
892 xmlParserInputPtr inputStream;
893 xmlParserInputBufferPtr buf;
894
895 ctxt = xmlNewParserCtxt();
896 if (ctxt == NULL) {
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000897#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000898 if (xmlDefaultSAXHandler.error != NULL) {
899 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
900 }
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000901#endif
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000902 return(NULL);
903 }
904
905 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
906 if (buf == NULL) {
907 xmlFreeParserCtxt(ctxt);
908 return(NULL);
909 }
910
911 inputStream = xmlNewInputStream(ctxt);
912 if (inputStream == NULL) {
913 xmlFreeParserCtxt(ctxt);
914 return(NULL);
915 }
916
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000917 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000918 inputStream->buf = buf;
Daniel Veillard61551a12012-07-16 16:28:47 +0800919 xmlBufResetInput(buf->buffer, inputStream);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000920
921 inputPush(ctxt, inputStream);
922 if ((ctxt->directory == NULL) && (directory == NULL))
923 directory = xmlParserGetDirectory(filename);
924 if ((ctxt->directory == NULL) && (directory != NULL))
925 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000926 ctxt->valid = 0;
927 ctxt->validate = 0;
928 ctxt->loadsubset = 0;
929 ctxt->pedantic = 0;
Daniel Veillard03a53c32004-10-26 16:06:51 +0000930 ctxt->dictNames = 1;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000931
932 xmlParseDocument(ctxt);
933
934 if (ctxt->wellFormed)
935 ret = ctxt->myDoc;
936 else {
937 ret = NULL;
938 xmlFreeDoc(ctxt->myDoc);
939 ctxt->myDoc = NULL;
940 }
941 xmlFreeParserCtxt(ctxt);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800942
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000943 return(ret);
944}
945
Daniel Veillard75b96822001-10-11 18:59:45 +0000946/**
947 * xmlLoadFileContent:
948 * @filename: a file path
949 *
950 * Load a file content into memory.
951 *
952 * Returns a pointer to the 0 terminated string or NULL in case of error
953 */
954static xmlChar *
955xmlLoadFileContent(const char *filename)
956{
957#ifdef HAVE_STAT
958 int fd;
959#else
960 FILE *fd;
961#endif
962 int len;
963 long size;
964
965#ifdef HAVE_STAT
966 struct stat info;
967#endif
968 xmlChar *content;
969
970 if (filename == NULL)
971 return (NULL);
972
973#ifdef HAVE_STAT
974 if (stat(filename, &info) < 0)
975 return (NULL);
976#endif
977
978#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000979 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000980#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000981 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000982#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000983 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000984 return (NULL);
985 }
986#ifdef HAVE_STAT
987 size = info.st_size;
988#else
989 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
990 fclose(fd);
991 return (NULL);
992 }
993#endif
Denis Pauke1631e12013-03-10 12:47:37 +0200994 content = (xmlChar*)xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000995 if (content == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000996 xmlCatalogErrMemory("allocating catalog data");
Daniel Veillard15d12042014-02-06 10:38:00 +0100997#ifdef HAVE_STAT
998 close(fd);
999#else
1000 fclose(fd);
1001#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00001002 return (NULL);
1003 }
1004#ifdef HAVE_STAT
1005 len = read(fd, content, size);
Carlo Braminic43ac662010-10-14 14:27:54 +02001006 close(fd);
Daniel Veillard75b96822001-10-11 18:59:45 +00001007#else
1008 len = fread(content, 1, size, fd);
Carlo Braminic43ac662010-10-14 14:27:54 +02001009 fclose(fd);
Daniel Veillard75b96822001-10-11 18:59:45 +00001010#endif
1011 if (len < 0) {
1012 xmlFree(content);
1013 return (NULL);
1014 }
Daniel Veillard75b96822001-10-11 18:59:45 +00001015 content[len] = 0;
1016
1017 return(content);
1018}
1019
Daniel Veillardc8155052004-07-16 09:03:08 +00001020/**
1021 * xmlCatalogNormalizePublic:
1022 * @pubID: the public ID string
1023 *
1024 * Normalizes the Public Identifier
1025 *
1026 * Implements 6.2. Public Identifier Normalization
1027 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1028 *
1029 * Returns the new string or NULL, the string must be deallocated
1030 * by the caller.
1031 */
1032static xmlChar *
1033xmlCatalogNormalizePublic(const xmlChar *pubID)
1034{
1035 int ok = 1;
1036 int white;
1037 const xmlChar *p;
1038 xmlChar *ret;
1039 xmlChar *q;
1040
1041 if (pubID == NULL)
1042 return(NULL);
1043
1044 white = 1;
1045 for (p = pubID;*p != 0 && ok;p++) {
1046 if (!xmlIsBlank_ch(*p))
1047 white = 0;
1048 else if (*p == 0x20 && !white)
1049 white = 1;
1050 else
1051 ok = 0;
1052 }
1053 if (ok && !white) /* is normalized */
1054 return(NULL);
1055
1056 ret = xmlStrdup(pubID);
1057 q = ret;
1058 white = 0;
1059 for (p = pubID;*p != 0;p++) {
1060 if (xmlIsBlank_ch(*p)) {
1061 if (q != ret)
1062 white = 1;
1063 } else {
1064 if (white) {
1065 *(q++) = 0x20;
1066 white = 0;
1067 }
1068 *(q++) = *p;
1069 }
1070 }
1071 *q = 0;
1072 return(ret);
1073}
1074
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001075/************************************************************************
1076 * *
Daniel Veillard344cee72001-08-20 00:08:40 +00001077 * The XML Catalog parser *
1078 * *
1079 ************************************************************************/
1080
1081static xmlCatalogEntryPtr
1082xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001083static void
1084xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001085 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
Daniel Veillardcda96922001-08-21 10:56:31 +00001086static xmlChar *
1087xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1088 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001089static xmlChar *
1090xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1091
Daniel Veillard344cee72001-08-20 00:08:40 +00001092
Daniel Veillard75b96822001-10-11 18:59:45 +00001093/**
1094 * xmlGetXMLCatalogEntryType:
1095 * @name: the name
1096 *
1097 * lookup the internal type associated to an XML catalog entry name
1098 *
Daniel Veillard06d25242004-02-25 13:01:42 +00001099 * Returns the type associated with that name
Daniel Veillard75b96822001-10-11 18:59:45 +00001100 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001101static xmlCatalogEntryType
1102xmlGetXMLCatalogEntryType(const xmlChar *name) {
1103 xmlCatalogEntryType type = XML_CATA_NONE;
1104 if (xmlStrEqual(name, (const xmlChar *) "system"))
1105 type = XML_CATA_SYSTEM;
1106 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1107 type = XML_CATA_PUBLIC;
1108 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1109 type = XML_CATA_REWRITE_SYSTEM;
1110 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1111 type = XML_CATA_DELEGATE_PUBLIC;
1112 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1113 type = XML_CATA_DELEGATE_SYSTEM;
1114 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1115 type = XML_CATA_URI;
1116 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1117 type = XML_CATA_REWRITE_URI;
1118 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1119 type = XML_CATA_DELEGATE_URI;
1120 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1121 type = XML_CATA_NEXT_CATALOG;
1122 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1123 type = XML_CATA_CATALOG;
1124 return(type);
1125}
1126
Daniel Veillard75b96822001-10-11 18:59:45 +00001127/**
1128 * xmlParseXMLCatalogOneNode:
1129 * @cur: the XML node
1130 * @type: the type of Catalog entry
1131 * @name: the name of the node
1132 * @attrName: the attribute holding the value
1133 * @uriAttrName: the attribute holding the URI-Reference
1134 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +00001135 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001136 *
1137 * Finishes the examination of an XML tree node of a catalog and build
1138 * a Catalog entry from it.
1139 *
1140 * Returns the new Catalog entry node or NULL in case of error.
1141 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001142static xmlCatalogEntryPtr
1143xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1144 const xmlChar *name, const xmlChar *attrName,
William M. Brackb7b54de2004-10-06 16:38:01 +00001145 const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1146 xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001147 int ok = 1;
1148 xmlChar *uriValue;
1149 xmlChar *nameValue = NULL;
1150 xmlChar *base = NULL;
1151 xmlChar *URL = NULL;
1152 xmlCatalogEntryPtr ret = NULL;
1153
1154 if (attrName != NULL) {
1155 nameValue = xmlGetProp(cur, attrName);
1156 if (nameValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001157 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1158 "%s entry lacks '%s'\n", name, attrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001159 ok = 0;
1160 }
1161 }
1162 uriValue = xmlGetProp(cur, uriAttrName);
1163 if (uriValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001164 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1165 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001166 ok = 0;
1167 }
1168 if (!ok) {
1169 if (nameValue != NULL)
1170 xmlFree(nameValue);
1171 if (uriValue != NULL)
1172 xmlFree(uriValue);
1173 return(NULL);
1174 }
1175
1176 base = xmlNodeGetBase(cur->doc, cur);
1177 URL = xmlBuildURI(uriValue, base);
1178 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001179 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001180 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001181 xmlGenericError(xmlGenericErrorContext,
1182 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001183 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001184 xmlGenericError(xmlGenericErrorContext,
1185 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001186 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001187 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001188 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001189 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
Daniel Veillard344cee72001-08-20 00:08:40 +00001190 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1191 }
1192 if (nameValue != NULL)
1193 xmlFree(nameValue);
1194 if (uriValue != NULL)
1195 xmlFree(uriValue);
1196 if (base != NULL)
1197 xmlFree(base);
1198 if (URL != NULL)
1199 xmlFree(URL);
1200 return(ret);
1201}
1202
Daniel Veillard75b96822001-10-11 18:59:45 +00001203/**
1204 * xmlParseXMLCatalogNode:
1205 * @cur: the XML node
1206 * @prefer: the PUBLIC vs. SYSTEM current preference value
1207 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001208 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001209 *
1210 * Examines an XML tree node of a catalog and build
1211 * a Catalog entry from it adding it to its parent. The examination can
1212 * be recursive.
1213 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001214static void
1215xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001216 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
Daniel Veillard344cee72001-08-20 00:08:40 +00001217{
Daniel Veillard344cee72001-08-20 00:08:40 +00001218 xmlChar *base = NULL;
1219 xmlCatalogEntryPtr entry = NULL;
1220
1221 if (cur == NULL)
1222 return;
1223 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1224 xmlChar *prop;
William M. Brackb7b54de2004-10-06 16:38:01 +00001225 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
Daniel Veillard344cee72001-08-20 00:08:40 +00001226
1227 prop = xmlGetProp(cur, BAD_CAST "prefer");
1228 if (prop != NULL) {
1229 if (xmlStrEqual(prop, BAD_CAST "system")) {
1230 prefer = XML_CATA_PREFER_SYSTEM;
1231 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1232 prefer = XML_CATA_PREFER_PUBLIC;
1233 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001234 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1235 "Invalid value for prefer: '%s'\n",
1236 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001237 }
1238 xmlFree(prop);
William M. Brackb7b54de2004-10-06 16:38:01 +00001239 pref = prefer;
Daniel Veillard344cee72001-08-20 00:08:40 +00001240 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001241 prop = xmlGetProp(cur, BAD_CAST "id");
1242 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1243 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
William M. Brack181a1ca2004-10-06 18:00:29 +00001244 xmlFree(prop);
Daniel Veillard344cee72001-08-20 00:08:40 +00001245 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1246 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
William M. Brackb7b54de2004-10-06 16:38:01 +00001247 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001248 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1249 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
William M. Brackb7b54de2004-10-06 16:38:01 +00001250 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001251 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1252 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1253 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001254 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001255 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1256 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1257 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001258 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001259 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1260 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1261 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001262 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001263 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1264 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1265 BAD_CAST "uri", BAD_CAST "name",
William M. Brackb7b54de2004-10-06 16:38:01 +00001266 BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001267 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1268 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1269 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001270 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001271 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1272 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1273 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001274 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001275 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1276 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1277 BAD_CAST "nextCatalog", NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001278 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001279 }
William M. Brackb031cef2004-11-05 16:34:22 +00001280 if (entry != NULL) {
1281 if (parent != NULL) {
1282 entry->parent = parent;
1283 if (parent->children == NULL)
1284 parent->children = entry;
1285 else {
1286 xmlCatalogEntryPtr prev;
Daniel Veillard344cee72001-08-20 00:08:40 +00001287
William M. Brackb031cef2004-11-05 16:34:22 +00001288 prev = parent->children;
1289 while (prev->next != NULL)
1290 prev = prev->next;
1291 prev->next = entry;
1292 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001293 }
William M. Brackb031cef2004-11-05 16:34:22 +00001294 if (entry->type == XML_CATA_GROUP) {
1295 /*
1296 * Recurse to propagate prefer to the subtree
1297 * (xml:base handling is automated)
1298 */
1299 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1300 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001301 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001302 if (base != NULL)
1303 xmlFree(base);
Daniel Veillard344cee72001-08-20 00:08:40 +00001304}
1305
Daniel Veillard75b96822001-10-11 18:59:45 +00001306/**
1307 * xmlParseXMLCatalogNodeList:
1308 * @cur: the XML node list of siblings
1309 * @prefer: the PUBLIC vs. SYSTEM current preference value
1310 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001311 * @cgroup: the group which includes this list
Daniel Veillard75b96822001-10-11 18:59:45 +00001312 *
1313 * Examines a list of XML sibling nodes of a catalog and build
1314 * a list of Catalog entry from it adding it to the parent.
1315 * The examination will recurse to examine node subtrees.
1316 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001317static void
1318xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001319 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001320 while (cur != NULL) {
1321 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1322 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
William M. Brackb7b54de2004-10-06 16:38:01 +00001323 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001324 }
1325 cur = cur->next;
1326 }
1327 /* TODO: sort the list according to REWRITE lengths and prefer value */
1328}
1329
Daniel Veillard75b96822001-10-11 18:59:45 +00001330/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001331 * xmlParseXMLCatalogFile:
1332 * @prefer: the PUBLIC vs. SYSTEM current preference value
1333 * @filename: the filename for the catalog
1334 *
1335 * Parses the catalog file to extract the XML tree and then analyze the
1336 * tree to build a list of Catalog entries corresponding to this catalog
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001337 *
Daniel Veillard75b96822001-10-11 18:59:45 +00001338 * Returns the resulting Catalog entries list
1339 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001340static xmlCatalogEntryPtr
1341xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1342 xmlDocPtr doc;
1343 xmlNodePtr cur;
1344 xmlChar *prop;
1345 xmlCatalogEntryPtr parent = NULL;
1346
1347 if (filename == NULL)
1348 return(NULL);
1349
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001350 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001351 if (doc == NULL) {
1352 if (xmlDebugCatalogs)
1353 xmlGenericError(xmlGenericErrorContext,
1354 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001355 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001356 }
1357
1358 if (xmlDebugCatalogs)
1359 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001360 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001361
1362 cur = xmlDocGetRootElement(doc);
1363 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1364 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1365 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1366
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001367 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001368 (const xmlChar *)filename, NULL, prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001369 if (parent == NULL) {
1370 xmlFreeDoc(doc);
1371 return(NULL);
1372 }
1373
1374 prop = xmlGetProp(cur, BAD_CAST "prefer");
1375 if (prop != NULL) {
1376 if (xmlStrEqual(prop, BAD_CAST "system")) {
1377 prefer = XML_CATA_PREFER_SYSTEM;
1378 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1379 prefer = XML_CATA_PREFER_PUBLIC;
1380 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001381 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1382 "Invalid value for prefer: '%s'\n",
1383 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001384 }
1385 xmlFree(prop);
1386 }
1387 cur = cur->children;
William M. Brackb7b54de2004-10-06 16:38:01 +00001388 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001389 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001390 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1391 "File %s is not an XML Catalog\n",
1392 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001393 xmlFreeDoc(doc);
1394 return(NULL);
1395 }
1396 xmlFreeDoc(doc);
1397 return(parent);
1398}
1399
Daniel Veillardcda96922001-08-21 10:56:31 +00001400/**
1401 * xmlFetchXMLCatalogFile:
1402 * @catal: an existing but incomplete catalog entry
1403 *
1404 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001405 *
Daniel Veillardcda96922001-08-21 10:56:31 +00001406 * Returns 0 in case of success, -1 otherwise
1407 */
1408static int
1409xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001410 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001411
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001412 if (catal == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001413 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001414 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001415 return(-1);
Daniel Veillardcda96922001-08-21 10:56:31 +00001416
Daniel Veillard81463942001-10-16 12:34:39 +00001417 /*
1418 * lock the whole catalog for modification
1419 */
1420 xmlRMutexLock(xmlCatalogMutex);
1421 if (catal->children != NULL) {
1422 /* Okay someone else did it in the meantime */
1423 xmlRMutexUnlock(xmlCatalogMutex);
1424 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001425 }
1426
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001427 if (xmlCatalogXMLFiles != NULL) {
1428 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001429 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001430 if (doc != NULL) {
1431 if (xmlDebugCatalogs)
1432 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001433 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001434
1435 if (catal->type == XML_CATA_CATALOG)
1436 catal->children = doc->children;
1437 else
1438 catal->children = doc;
1439 catal->dealloc = 0;
1440 xmlRMutexUnlock(xmlCatalogMutex);
1441 return(0);
1442 }
1443 if (xmlDebugCatalogs)
1444 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001445 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001446 }
1447
Daniel Veillardcda96922001-08-21 10:56:31 +00001448 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001449 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001450 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001451 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001452 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001453 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001454 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001455 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001456 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001457 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001458 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001459
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001460 if (catal->type == XML_CATA_CATALOG)
1461 catal->children = doc->children;
1462 else
1463 catal->children = doc;
1464
1465 doc->dealloc = 1;
1466
Daniel Veillard81463942001-10-16 12:34:39 +00001467 if (xmlCatalogXMLFiles == NULL)
1468 xmlCatalogXMLFiles = xmlHashCreate(10);
1469 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001470 if (xmlDebugCatalogs)
1471 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001472 "%s added to file hash\n", catal->URL);
1473 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001474 }
Daniel Veillard81463942001-10-16 12:34:39 +00001475 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001476 return(0);
1477}
1478
Daniel Veillard75b96822001-10-11 18:59:45 +00001479/************************************************************************
1480 * *
1481 * XML Catalog handling *
1482 * *
1483 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001484
1485/**
1486 * xmlAddXMLCatalog:
1487 * @catal: top of an XML catalog
1488 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001489 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001490 * @replace: the replacement value for the match
1491 *
1492 * Add an entry in the XML catalog, it may overwrite existing but
1493 * different entries.
1494 *
1495 * Returns 0 if successful, -1 otherwise
1496 */
1497static int
1498xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1499 const xmlChar *orig, const xmlChar *replace) {
1500 xmlCatalogEntryPtr cur;
1501 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001502 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001503
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001504 if ((catal == NULL) ||
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001505 ((catal->type != XML_CATA_CATALOG) &&
1506 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001507 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001508 if (catal->children == NULL) {
1509 xmlFetchXMLCatalogFile(catal);
1510 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001511 if (catal->children == NULL)
1512 doregister = 1;
1513
Daniel Veillard344cee72001-08-20 00:08:40 +00001514 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001515 if (typ == XML_CATA_NONE) {
1516 if (xmlDebugCatalogs)
1517 xmlGenericError(xmlGenericErrorContext,
1518 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001519 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001520 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001521
1522 cur = catal->children;
1523 /*
1524 * Might be a simple "update in place"
1525 */
1526 if (cur != NULL) {
1527 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001528 if ((orig != NULL) && (cur->type == typ) &&
1529 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001530 if (xmlDebugCatalogs)
1531 xmlGenericError(xmlGenericErrorContext,
1532 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001533 if (cur->value != NULL)
1534 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001535 if (cur->URL != NULL)
1536 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001537 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001538 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001539 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001540 }
1541 if (cur->next == NULL)
1542 break;
1543 cur = cur->next;
1544 }
1545 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001546 if (xmlDebugCatalogs)
1547 xmlGenericError(xmlGenericErrorContext,
1548 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001549 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001550 catal->children = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001551 NULL, catal->prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001552 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001553 cur->next = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001554 NULL, catal->prefer, NULL);
Daniel Veillardc853b322001-11-06 15:24:37 +00001555 if (doregister) {
Daniel Veillard27bec142006-02-24 20:22:27 +00001556 catal->type = XML_CATA_CATALOG;
Denis Pauke1631e12013-03-10 12:47:37 +02001557 cur = (xmlCatalogEntryPtr)xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillardc853b322001-11-06 15:24:37 +00001558 if (cur != NULL)
1559 cur->children = catal->children;
1560 }
1561
Daniel Veillardcda96922001-08-21 10:56:31 +00001562 return(0);
1563}
1564
1565/**
1566 * xmlDelXMLCatalog:
1567 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001568 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001569 *
1570 * Remove entries in the XML catalog where the value or the URI
1571 * is equal to @value
1572 *
1573 * Returns the number of entries removed if successful, -1 otherwise
1574 */
1575static int
1576xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001577 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001578 int ret = 0;
1579
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001580 if ((catal == NULL) ||
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001581 ((catal->type != XML_CATA_CATALOG) &&
1582 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001583 return(-1);
1584 if (value == NULL)
1585 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001586 if (catal->children == NULL) {
1587 xmlFetchXMLCatalogFile(catal);
1588 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001589
1590 /*
1591 * Scan the children
1592 */
1593 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001594 while (cur != NULL) {
1595 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1596 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001597 if (xmlDebugCatalogs) {
1598 if (cur->name != NULL)
1599 xmlGenericError(xmlGenericErrorContext,
1600 "Removing element %s from catalog\n", cur->name);
1601 else
1602 xmlGenericError(xmlGenericErrorContext,
1603 "Removing element %s from catalog\n", cur->value);
1604 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001605 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001606 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001607 cur = cur->next;
1608 }
1609 return(ret);
1610}
1611
1612/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001613 * xmlCatalogXMLResolve:
1614 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001615 * @pubID: the public ID string
1616 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001617 *
1618 * Do a complete resolution lookup of an External Identifier for a
1619 * list of catalog entries.
1620 *
1621 * Implements (or tries to) 7.1. External Identifier Resolution
1622 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1623 *
1624 * Returns the URI of the resource or NULL if not found
1625 */
1626static xmlChar *
1627xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1628 const xmlChar *sysID) {
1629 xmlChar *ret = NULL;
1630 xmlCatalogEntryPtr cur;
1631 int haveDelegate = 0;
1632 int haveNext = 0;
1633
1634 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001635 * protection against loops
1636 */
1637 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001638 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1639 "Detected recursion in catalog %s\n",
1640 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001641 return(NULL);
1642 }
1643 catal->depth++;
1644
1645 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001646 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1647 */
1648 if (sysID != NULL) {
1649 xmlCatalogEntryPtr rewrite = NULL;
1650 int lenrewrite = 0, len;
1651 cur = catal;
1652 haveDelegate = 0;
1653 while (cur != NULL) {
1654 switch (cur->type) {
1655 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001656 if (xmlStrEqual(sysID, cur->name)) {
1657 if (xmlDebugCatalogs)
1658 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard890b5492006-02-23 08:14:00 +00001659 "Found system match %s, using %s\n",
1660 cur->name, cur->URL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001661 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001662 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001663 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001664 break;
1665 case XML_CATA_REWRITE_SYSTEM:
1666 len = xmlStrlen(cur->name);
1667 if ((len > lenrewrite) &&
1668 (!xmlStrncmp(sysID, cur->name, len))) {
1669 lenrewrite = len;
1670 rewrite = cur;
1671 }
1672 break;
1673 case XML_CATA_DELEGATE_SYSTEM:
1674 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1675 haveDelegate++;
1676 break;
1677 case XML_CATA_NEXT_CATALOG:
1678 haveNext++;
1679 break;
1680 default:
1681 break;
1682 }
1683 cur = cur->next;
1684 }
1685 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001686 if (xmlDebugCatalogs)
1687 xmlGenericError(xmlGenericErrorContext,
1688 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001689 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001690 if (ret != NULL)
1691 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001692 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001693 return(ret);
1694 }
1695 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001696 const xmlChar *delegates[MAX_DELEGATE];
1697 int nbList = 0, i;
1698
Daniel Veillardcda96922001-08-21 10:56:31 +00001699 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001700 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001701 * matches when the list was produced.
1702 */
1703 cur = catal;
1704 while (cur != NULL) {
1705 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1706 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001707 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001708 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001709 break;
1710 if (i < nbList) {
1711 cur = cur->next;
1712 continue;
1713 }
1714 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001715 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001716
Daniel Veillardcda96922001-08-21 10:56:31 +00001717 if (cur->children == NULL) {
1718 xmlFetchXMLCatalogFile(cur);
1719 }
1720 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001721 if (xmlDebugCatalogs)
1722 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001723 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001724 ret = xmlCatalogListXMLResolve(
1725 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001726 if (ret != NULL) {
1727 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001728 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001729 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001730 }
1731 }
1732 cur = cur->next;
1733 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001734 /*
1735 * Apply the cut algorithm explained in 4/
1736 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001737 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001738 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001739 }
1740 }
1741 /*
1742 * Then tries 5/ 6/ if a public ID is provided
1743 */
1744 if (pubID != NULL) {
1745 cur = catal;
1746 haveDelegate = 0;
1747 while (cur != NULL) {
1748 switch (cur->type) {
1749 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001750 if (xmlStrEqual(pubID, cur->name)) {
1751 if (xmlDebugCatalogs)
1752 xmlGenericError(xmlGenericErrorContext,
1753 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001754 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001755 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001756 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001757 break;
1758 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001759 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1760 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001761 haveDelegate++;
1762 break;
1763 case XML_CATA_NEXT_CATALOG:
1764 if (sysID == NULL)
1765 haveNext++;
1766 break;
1767 default:
1768 break;
1769 }
1770 cur = cur->next;
1771 }
1772 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001773 const xmlChar *delegates[MAX_DELEGATE];
1774 int nbList = 0, i;
1775
Daniel Veillardcda96922001-08-21 10:56:31 +00001776 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001777 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001778 * matches when the list was produced.
1779 */
1780 cur = catal;
1781 while (cur != NULL) {
1782 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001783 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1784 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001785
1786 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001787 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001788 break;
1789 if (i < nbList) {
1790 cur = cur->next;
1791 continue;
1792 }
1793 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001794 delegates[nbList++] = cur->URL;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001795
Daniel Veillardcda96922001-08-21 10:56:31 +00001796 if (cur->children == NULL) {
1797 xmlFetchXMLCatalogFile(cur);
1798 }
1799 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001800 if (xmlDebugCatalogs)
1801 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001802 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001803 ret = xmlCatalogListXMLResolve(
1804 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001805 if (ret != NULL) {
1806 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001807 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001808 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001809 }
1810 }
1811 cur = cur->next;
1812 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001813 /*
1814 * Apply the cut algorithm explained in 4/
1815 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001816 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001817 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001818 }
1819 }
1820 if (haveNext) {
1821 cur = catal;
1822 while (cur != NULL) {
1823 if (cur->type == XML_CATA_NEXT_CATALOG) {
1824 if (cur->children == NULL) {
1825 xmlFetchXMLCatalogFile(cur);
1826 }
1827 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001828 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001829 if (ret != NULL) {
1830 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001831 return(ret);
Daniel Veillardbe8d9d32007-06-12 09:14:11 +00001832 } else if (catal->depth > MAX_CATAL_DEPTH) {
1833 return(NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001834 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001835 }
1836 }
1837 cur = cur->next;
1838 }
1839 }
1840
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001841 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001842 return(NULL);
1843}
1844
1845/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001846 * xmlCatalogXMLResolveURI:
1847 * @catal: a catalog list
1848 * @URI: the URI
Daniel Veillard06d25242004-02-25 13:01:42 +00001849 * @sysID: the system ID string
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001850 *
1851 * Do a complete resolution lookup of an External Identifier for a
1852 * list of catalog entries.
1853 *
1854 * Implements (or tries to) 7.2.2. URI Resolution
1855 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1856 *
1857 * Returns the URI of the resource or NULL if not found
1858 */
1859static xmlChar *
1860xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1861 xmlChar *ret = NULL;
1862 xmlCatalogEntryPtr cur;
1863 int haveDelegate = 0;
1864 int haveNext = 0;
1865 xmlCatalogEntryPtr rewrite = NULL;
1866 int lenrewrite = 0, len;
1867
1868 if (catal == NULL)
1869 return(NULL);
1870
1871 if (URI == NULL)
1872 return(NULL);
1873
Daniel Veillardbe8d9d32007-06-12 09:14:11 +00001874 if (catal->depth > MAX_CATAL_DEPTH) {
1875 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1876 "Detected recursion in catalog %s\n",
1877 catal->name, NULL, NULL);
1878 return(NULL);
1879 }
1880
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001881 /*
1882 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1883 */
1884 cur = catal;
1885 haveDelegate = 0;
1886 while (cur != NULL) {
1887 switch (cur->type) {
1888 case XML_CATA_URI:
1889 if (xmlStrEqual(URI, cur->name)) {
1890 if (xmlDebugCatalogs)
1891 xmlGenericError(xmlGenericErrorContext,
1892 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001893 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001894 }
1895 break;
1896 case XML_CATA_REWRITE_URI:
1897 len = xmlStrlen(cur->name);
1898 if ((len > lenrewrite) &&
1899 (!xmlStrncmp(URI, cur->name, len))) {
1900 lenrewrite = len;
1901 rewrite = cur;
1902 }
1903 break;
1904 case XML_CATA_DELEGATE_URI:
1905 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1906 haveDelegate++;
1907 break;
1908 case XML_CATA_NEXT_CATALOG:
1909 haveNext++;
1910 break;
1911 default:
1912 break;
1913 }
1914 cur = cur->next;
1915 }
1916 if (rewrite != NULL) {
1917 if (xmlDebugCatalogs)
1918 xmlGenericError(xmlGenericErrorContext,
1919 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001920 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001921 if (ret != NULL)
1922 ret = xmlStrcat(ret, &URI[lenrewrite]);
1923 return(ret);
1924 }
1925 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001926 const xmlChar *delegates[MAX_DELEGATE];
1927 int nbList = 0, i;
1928
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001929 /*
1930 * Assume the entries have been sorted by decreasing substring
1931 * matches when the list was produced.
1932 */
1933 cur = catal;
1934 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001935 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1936 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001937 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001938 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001939 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001940 break;
1941 if (i < nbList) {
1942 cur = cur->next;
1943 continue;
1944 }
1945 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001946 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001947
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001948 if (cur->children == NULL) {
1949 xmlFetchXMLCatalogFile(cur);
1950 }
1951 if (cur->children != NULL) {
1952 if (xmlDebugCatalogs)
1953 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001954 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001955 ret = xmlCatalogListXMLResolveURI(
1956 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001957 if (ret != NULL)
1958 return(ret);
1959 }
1960 }
1961 cur = cur->next;
1962 }
1963 /*
1964 * Apply the cut algorithm explained in 4/
1965 */
1966 return(XML_CATAL_BREAK);
1967 }
1968 if (haveNext) {
1969 cur = catal;
1970 while (cur != NULL) {
1971 if (cur->type == XML_CATA_NEXT_CATALOG) {
1972 if (cur->children == NULL) {
1973 xmlFetchXMLCatalogFile(cur);
1974 }
1975 if (cur->children != NULL) {
1976 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1977 if (ret != NULL)
1978 return(ret);
1979 }
1980 }
1981 cur = cur->next;
1982 }
1983 }
1984
1985 return(NULL);
1986}
1987
1988/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001989 * xmlCatalogListXMLResolve:
1990 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001991 * @pubID: the public ID string
1992 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001993 *
1994 * Do a complete resolution lookup of an External Identifier for a
1995 * list of catalogs
1996 *
1997 * Implements (or tries to) 7.1. External Identifier Resolution
1998 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1999 *
2000 * Returns the URI of the resource or NULL if not found
2001 */
2002static xmlChar *
2003xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
2004 const xmlChar *sysID) {
2005 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002006 xmlChar *urnID = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +00002007 xmlChar *normid;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002008
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002009 if (catal == NULL)
2010 return(NULL);
2011 if ((pubID == NULL) && (sysID == NULL))
2012 return(NULL);
2013
Daniel Veillardc8155052004-07-16 09:03:08 +00002014 normid = xmlCatalogNormalizePublic(pubID);
2015 if (normid != NULL)
2016 pubID = (*normid != 0 ? normid : NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002017
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002018 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2019 urnID = xmlCatalogUnWrapURN(pubID);
2020 if (xmlDebugCatalogs) {
2021 if (urnID == NULL)
2022 xmlGenericError(xmlGenericErrorContext,
2023 "Public URN ID %s expanded to NULL\n", pubID);
2024 else
2025 xmlGenericError(xmlGenericErrorContext,
2026 "Public URN ID expanded to %s\n", urnID);
2027 }
2028 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2029 if (urnID != NULL)
2030 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002031 if (normid != NULL)
2032 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002033 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002034 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002035 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2036 urnID = xmlCatalogUnWrapURN(sysID);
2037 if (xmlDebugCatalogs) {
2038 if (urnID == NULL)
2039 xmlGenericError(xmlGenericErrorContext,
2040 "System URN ID %s expanded to NULL\n", sysID);
2041 else
2042 xmlGenericError(xmlGenericErrorContext,
2043 "System URN ID expanded to %s\n", urnID);
2044 }
2045 if (pubID == NULL)
2046 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2047 else if (xmlStrEqual(pubID, urnID))
2048 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2049 else {
Daniel Veillard770075b2004-02-25 10:44:30 +00002050 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002051 }
2052 if (urnID != NULL)
2053 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002054 if (normid != NULL)
2055 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002056 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002057 }
2058 while (catal != NULL) {
2059 if (catal->type == XML_CATA_CATALOG) {
2060 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002061 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00002062 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002063 if (catal->children != NULL) {
2064 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002065 if (ret != NULL) {
Daniel Veillardbe8d9d32007-06-12 09:14:11 +00002066 break;
2067 } else if ((catal->children != NULL) &&
2068 (catal->children->depth > MAX_CATAL_DEPTH)) {
2069 ret = NULL;
2070 break;
2071 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002072 }
Daniel Veillardcda96922001-08-21 10:56:31 +00002073 }
2074 catal = catal->next;
2075 }
Daniel Veillardbe8d9d32007-06-12 09:14:11 +00002076 if (normid != NULL)
2077 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002078 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00002079}
2080
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002081/**
2082 * xmlCatalogListXMLResolveURI:
2083 * @catal: a catalog list
2084 * @URI: the URI
2085 *
2086 * Do a complete resolution lookup of an URI for a list of catalogs
2087 *
2088 * Implements (or tries to) 7.2. URI Resolution
2089 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2090 *
2091 * Returns the URI of the resource or NULL if not found
2092 */
2093static xmlChar *
2094xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2095 xmlChar *ret = NULL;
2096 xmlChar *urnID = NULL;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002097
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002098 if (catal == NULL)
2099 return(NULL);
2100 if (URI == NULL)
2101 return(NULL);
2102
2103 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2104 urnID = xmlCatalogUnWrapURN(URI);
2105 if (xmlDebugCatalogs) {
2106 if (urnID == NULL)
2107 xmlGenericError(xmlGenericErrorContext,
2108 "URN ID %s expanded to NULL\n", URI);
2109 else
2110 xmlGenericError(xmlGenericErrorContext,
2111 "URN ID expanded to %s\n", urnID);
2112 }
2113 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2114 if (urnID != NULL)
2115 xmlFree(urnID);
2116 return(ret);
2117 }
2118 while (catal != NULL) {
2119 if (catal->type == XML_CATA_CATALOG) {
2120 if (catal->children == NULL) {
2121 xmlFetchXMLCatalogFile(catal);
2122 }
2123 if (catal->children != NULL) {
2124 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2125 if (ret != NULL)
2126 return(ret);
2127 }
2128 }
2129 catal = catal->next;
2130 }
2131 return(ret);
2132}
2133
Daniel Veillard344cee72001-08-20 00:08:40 +00002134/************************************************************************
2135 * *
2136 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00002137 * *
2138 ************************************************************************/
2139
2140
2141#define RAW *cur
2142#define NEXT cur++;
2143#define SKIP(x) cur += x;
2144
William M. Brack272693c2003-11-14 16:20:34 +00002145#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002146
Daniel Veillard75b96822001-10-11 18:59:45 +00002147/**
2148 * xmlParseSGMLCatalogComment:
2149 * @cur: the current character
2150 *
2151 * Skip a comment in an SGML catalog
2152 *
2153 * Returns new current character
2154 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002155static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002156xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002157 if ((cur[0] != '-') || (cur[1] != '-'))
Daniel Veillarda7374592001-05-10 14:17:55 +00002158 return(cur);
2159 SKIP(2);
2160 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2161 NEXT;
2162 if (cur[0] == 0) {
2163 return(NULL);
2164 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002165 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00002166}
2167
Daniel Veillard75b96822001-10-11 18:59:45 +00002168/**
2169 * xmlParseSGMLCatalogPubid:
2170 * @cur: the current character
2171 * @id: the return location
2172 *
2173 * Parse an SGML catalog ID
2174 *
2175 * Returns new current character and store the value in @id
2176 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002177static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002178xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002179 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002180 int len = 0;
2181 int size = 50;
2182 xmlChar stop;
2183 int count = 0;
2184
2185 *id = NULL;
2186
2187 if (RAW == '"') {
2188 NEXT;
2189 stop = '"';
2190 } else if (RAW == '\'') {
2191 NEXT;
2192 stop = '\'';
2193 } else {
2194 stop = ' ';
2195 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002196 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002197 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002198 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002199 return(NULL);
2200 }
William M. Brack76e95df2003-10-18 16:20:14 +00002201 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002202 if ((*cur == stop) && (stop != ' '))
2203 break;
William M. Brack76e95df2003-10-18 16:20:14 +00002204 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
Daniel Veillarda7374592001-05-10 14:17:55 +00002205 break;
2206 if (len + 1 >= size) {
2207 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002208 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2209 if (tmp == NULL) {
2210 xmlCatalogErrMemory("allocating public ID");
2211 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002212 return(NULL);
2213 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002214 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002215 }
2216 buf[len++] = *cur;
2217 count++;
2218 NEXT;
2219 }
2220 buf[len] = 0;
2221 if (stop == ' ') {
William M. Brack76e95df2003-10-18 16:20:14 +00002222 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002223 xmlFree(buf);
2224 return(NULL);
2225 }
2226 } else {
2227 if (*cur != stop) {
2228 xmlFree(buf);
2229 return(NULL);
2230 }
2231 NEXT;
2232 }
2233 *id = buf;
2234 return(cur);
2235}
2236
Daniel Veillard75b96822001-10-11 18:59:45 +00002237/**
2238 * xmlParseSGMLCatalogName:
2239 * @cur: the current character
2240 * @name: the return location
2241 *
2242 * Parse an SGML catalog name
2243 *
2244 * Returns new current character and store the value in @name
2245 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002246static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002247xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002248 xmlChar buf[XML_MAX_NAMELEN + 5];
2249 int len = 0;
2250 int c;
2251
2252 *name = NULL;
2253
2254 /*
2255 * Handler for more complex cases
2256 */
2257 c = *cur;
2258 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2259 return(NULL);
2260 }
2261
2262 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2263 (c == '.') || (c == '-') ||
2264 (c == '_') || (c == ':'))) {
2265 buf[len++] = c;
2266 cur++;
2267 c = *cur;
2268 if (len >= XML_MAX_NAMELEN)
2269 return(NULL);
2270 }
2271 *name = xmlStrndup(buf, len);
2272 return(cur);
2273}
2274
Daniel Veillard75b96822001-10-11 18:59:45 +00002275/**
2276 * xmlGetSGMLCatalogEntryType:
2277 * @name: the entry name
2278 *
2279 * Get the Catalog entry type for a given SGML Catalog name
2280 *
2281 * Returns Catalog entry type
2282 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002283static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002284xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002285 xmlCatalogEntryType type = XML_CATA_NONE;
2286 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2287 type = SGML_CATA_SYSTEM;
2288 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2289 type = SGML_CATA_PUBLIC;
2290 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2291 type = SGML_CATA_DELEGATE;
2292 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2293 type = SGML_CATA_ENTITY;
2294 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2295 type = SGML_CATA_DOCTYPE;
2296 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2297 type = SGML_CATA_LINKTYPE;
2298 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2299 type = SGML_CATA_NOTATION;
2300 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2301 type = SGML_CATA_SGMLDECL;
2302 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2303 type = SGML_CATA_DOCUMENT;
2304 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2305 type = SGML_CATA_CATALOG;
2306 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2307 type = SGML_CATA_BASE;
Daniel Veillard344cee72001-08-20 00:08:40 +00002308 return(type);
2309}
2310
Daniel Veillard75b96822001-10-11 18:59:45 +00002311/**
2312 * xmlParseSGMLCatalog:
2313 * @catal: the SGML Catalog
2314 * @value: the content of the SGML Catalog serialization
2315 * @file: the filepath for the catalog
2316 * @super: should this be handled as a Super Catalog in which case
2317 * parsing is not recursive
2318 *
2319 * Parse an SGML catalog content and fill up the @catal hash table with
2320 * the new entries found.
2321 *
2322 * Returns 0 in case of success, -1 in case of error.
2323 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002324static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002325xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2326 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002327 const xmlChar *cur = value;
2328 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002329 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002330
2331 if ((cur == NULL) || (file == NULL))
2332 return(-1);
2333 base = xmlStrdup((const xmlChar *) file);
2334
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002335 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002336 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002337 if (cur[0] == 0)
2338 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002339 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002340 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002341 if (cur == NULL) {
2342 /* error */
2343 break;
2344 }
2345 } else {
2346 xmlChar *sysid = NULL;
2347 xmlChar *name = NULL;
2348 xmlCatalogEntryType type = XML_CATA_NONE;
2349
Daniel Veillardcda96922001-08-21 10:56:31 +00002350 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002351 if (name == NULL) {
2352 /* error */
2353 break;
2354 }
William M. Brack76e95df2003-10-18 16:20:14 +00002355 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002356 /* error */
2357 break;
2358 }
2359 SKIP_BLANKS;
2360 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002361 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002362 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002363 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002364 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002365 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002366 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002367 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002368 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002369 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002370 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002371 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002372 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002373 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002374 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002375 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002376 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002377 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002378 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002379 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002380 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002381 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002382 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2383 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002384 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002385 if (name == NULL) {
2386 /* error */
2387 break;
2388 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002389 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002390 continue;
2391 }
2392 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002393 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002394
2395 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002396 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002397 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002398 type = SGML_CATA_PENTITY;
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +02002399 /* Falls through. */
Daniel Veillard344cee72001-08-20 00:08:40 +00002400 case SGML_CATA_PENTITY:
2401 case SGML_CATA_DOCTYPE:
2402 case SGML_CATA_LINKTYPE:
2403 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002404 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002405 if (cur == NULL) {
2406 /* error */
2407 break;
2408 }
William M. Brack76e95df2003-10-18 16:20:14 +00002409 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002410 /* error */
2411 break;
2412 }
2413 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002414 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002415 if (cur == NULL) {
2416 /* error */
2417 break;
2418 }
2419 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002420 case SGML_CATA_PUBLIC:
2421 case SGML_CATA_SYSTEM:
2422 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002423 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002424 if (cur == NULL) {
2425 /* error */
2426 break;
2427 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002428 if (type != SGML_CATA_SYSTEM) {
2429 xmlChar *normid;
2430
2431 normid = xmlCatalogNormalizePublic(name);
2432 if (normid != NULL) {
2433 if (name != NULL)
2434 xmlFree(name);
2435 if (*normid != 0)
2436 name = normid;
2437 else {
2438 xmlFree(normid);
2439 name = NULL;
2440 }
2441 }
2442 }
William M. Brack76e95df2003-10-18 16:20:14 +00002443 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002444 /* error */
2445 break;
2446 }
2447 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002448 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002449 if (cur == NULL) {
2450 /* error */
2451 break;
2452 }
2453 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002454 case SGML_CATA_BASE:
2455 case SGML_CATA_CATALOG:
2456 case SGML_CATA_DOCUMENT:
2457 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002458 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002459 if (cur == NULL) {
2460 /* error */
2461 break;
2462 }
2463 break;
2464 default:
2465 break;
2466 }
2467 if (cur == NULL) {
2468 if (name != NULL)
2469 xmlFree(name);
2470 if (sysid != NULL)
2471 xmlFree(sysid);
2472 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002473 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002474 if (base != NULL)
2475 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002476 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002477 } else if ((type == SGML_CATA_PUBLIC) ||
2478 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002479 xmlChar *filename;
2480
2481 filename = xmlBuildURI(sysid, base);
2482 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002483 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002484
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002485 entry = xmlNewCatalogEntry(type, name, filename,
William M. Brackb7b54de2004-10-06 16:38:01 +00002486 NULL, XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002487 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002488 if (res < 0) {
2489 xmlFreeCatalogEntry(entry);
2490 }
2491 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002492 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002493
Daniel Veillard344cee72001-08-20 00:08:40 +00002494 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002495 if (super) {
2496 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002497
Daniel Veillardc853b322001-11-06 15:24:37 +00002498 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002499 XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002500 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002501 if (res < 0) {
2502 xmlFreeCatalogEntry(entry);
2503 }
2504 } else {
2505 xmlChar *filename;
2506
2507 filename = xmlBuildURI(sysid, base);
2508 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002509 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002510 xmlFree(filename);
2511 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002512 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002513 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002514 /*
2515 * drop anything else we won't handle it
2516 */
2517 if (name != NULL)
2518 xmlFree(name);
2519 if (sysid != NULL)
2520 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002521 }
2522 }
2523 if (base != NULL)
2524 xmlFree(base);
2525 if (cur == NULL)
2526 return(-1);
2527 return(0);
2528}
2529
Daniel Veillard75b96822001-10-11 18:59:45 +00002530/************************************************************************
2531 * *
2532 * SGML Catalog handling *
2533 * *
2534 ************************************************************************/
2535
Daniel Veillardcda96922001-08-21 10:56:31 +00002536/**
2537 * xmlCatalogGetSGMLPublic:
2538 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002539 * @pubID: the public ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002540 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002541 * Try to lookup the catalog local reference associated to a public ID
Daniel Veillardcda96922001-08-21 10:56:31 +00002542 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002543 * Returns the local resource if found or NULL otherwise.
Daniel Veillardcda96922001-08-21 10:56:31 +00002544 */
2545static const xmlChar *
2546xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2547 xmlCatalogEntryPtr entry;
Daniel Veillardc8155052004-07-16 09:03:08 +00002548 xmlChar *normid;
Daniel Veillardcda96922001-08-21 10:56:31 +00002549
2550 if (catal == NULL)
2551 return(NULL);
2552
Daniel Veillardc8155052004-07-16 09:03:08 +00002553 normid = xmlCatalogNormalizePublic(pubID);
2554 if (normid != NULL)
2555 pubID = (*normid != 0 ? normid : NULL);
2556
Daniel Veillardcda96922001-08-21 10:56:31 +00002557 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002558 if (entry == NULL) {
2559 if (normid != NULL)
2560 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002561 return(NULL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002562 }
2563 if (entry->type == SGML_CATA_PUBLIC) {
2564 if (normid != NULL)
2565 xmlFree(normid);
Daniel Veillardc853b322001-11-06 15:24:37 +00002566 return(entry->URL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002567 }
2568 if (normid != NULL)
2569 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002570 return(NULL);
2571}
2572
2573/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002574 * xmlCatalogGetSGMLSystem:
2575 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002576 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002577 *
2578 * Try to lookup the catalog local reference for a system ID
2579 *
Daniel Veillard770075b2004-02-25 10:44:30 +00002580 * Returns the local resource if found or NULL otherwise.
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002581 */
2582static const xmlChar *
2583xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2584 xmlCatalogEntryPtr entry;
2585
2586 if (catal == NULL)
2587 return(NULL);
2588
2589 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2590 if (entry == NULL)
2591 return(NULL);
2592 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002593 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002594 return(NULL);
2595}
2596
2597/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002598 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002599 * @catal: the SGML catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002600 * @pubID: the public ID string
2601 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002602 *
2603 * Do a complete resolution lookup of an External Identifier
2604 *
2605 * Returns the URI of the resource or NULL if not found
2606 */
2607static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002608xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2609 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002610 const xmlChar *ret = NULL;
2611
Daniel Veillard75b96822001-10-11 18:59:45 +00002612 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002613 return(NULL);
2614
2615 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002616 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002617 if (ret != NULL)
2618 return(ret);
2619 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002620 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillard63806b52008-06-10 14:56:11 +00002621 if (ret != NULL)
2622 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002623 return(NULL);
2624}
2625
Daniel Veillarda7374592001-05-10 14:17:55 +00002626/************************************************************************
2627 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002628 * Specific Public interfaces *
2629 * *
2630 ************************************************************************/
2631
2632/**
2633 * xmlLoadSGMLSuperCatalog:
2634 * @filename: a file path
2635 *
2636 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2637 * references. This is only needed for manipulating SGML Super Catalogs
2638 * like adding and removing CATALOG or DELEGATE entries.
2639 *
2640 * Returns the catalog parsed or NULL in case of error
2641 */
2642xmlCatalogPtr
2643xmlLoadSGMLSuperCatalog(const char *filename)
2644{
2645 xmlChar *content;
2646 xmlCatalogPtr catal;
2647 int ret;
2648
2649 content = xmlLoadFileContent(filename);
2650 if (content == NULL)
2651 return(NULL);
2652
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002653 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002654 if (catal == NULL) {
2655 xmlFree(content);
2656 return(NULL);
2657 }
2658
2659 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2660 xmlFree(content);
2661 if (ret < 0) {
2662 xmlFreeCatalog(catal);
2663 return(NULL);
2664 }
2665 return (catal);
2666}
2667
2668/**
2669 * xmlLoadACatalog:
2670 * @filename: a file path
2671 *
2672 * Load the catalog and build the associated data structures.
2673 * This can be either an XML Catalog or an SGML Catalog
2674 * It will recurse in SGML CATALOG entries. On the other hand XML
2675 * Catalogs are not handled recursively.
2676 *
2677 * Returns the catalog parsed or NULL in case of error
2678 */
2679xmlCatalogPtr
2680xmlLoadACatalog(const char *filename)
2681{
2682 xmlChar *content;
2683 xmlChar *first;
2684 xmlCatalogPtr catal;
2685 int ret;
2686
2687 content = xmlLoadFileContent(filename);
2688 if (content == NULL)
2689 return(NULL);
2690
2691
2692 first = content;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002693
Daniel Veillard75b96822001-10-11 18:59:45 +00002694 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2695 (!(((*first >= 'A') && (*first <= 'Z')) ||
2696 ((*first >= 'a') && (*first <= 'z')))))
2697 first++;
2698
2699 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002700 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002701 if (catal == NULL) {
2702 xmlFree(content);
2703 return(NULL);
2704 }
2705 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2706 if (ret < 0) {
2707 xmlFreeCatalog(catal);
2708 xmlFree(content);
2709 return(NULL);
2710 }
2711 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002712 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002713 if (catal == NULL) {
2714 xmlFree(content);
2715 return(NULL);
2716 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002717 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002718 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002719 }
2720 xmlFree(content);
2721 return (catal);
2722}
2723
2724/**
2725 * xmlExpandCatalog:
2726 * @catal: a catalog
2727 * @filename: a file path
2728 *
2729 * Load the catalog and expand the existing catal structure.
2730 * This can be either an XML Catalog or an SGML Catalog
2731 *
2732 * Returns 0 in case of success, -1 in case of error
2733 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002734static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002735xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2736{
Daniel Veillard75b96822001-10-11 18:59:45 +00002737 int ret;
2738
2739 if ((catal == NULL) || (filename == NULL))
2740 return(-1);
2741
Daniel Veillard75b96822001-10-11 18:59:45 +00002742
2743 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002744 xmlChar *content;
2745
2746 content = xmlLoadFileContent(filename);
2747 if (content == NULL)
2748 return(-1);
2749
Daniel Veillard75b96822001-10-11 18:59:45 +00002750 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2751 if (ret < 0) {
2752 xmlFree(content);
2753 return(-1);
2754 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002755 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002756 } else {
2757 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002758 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002759 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002760
Daniel Veillard75b96822001-10-11 18:59:45 +00002761 cur = catal->xml;
2762 if (cur == NULL) {
2763 catal->xml = tmp;
2764 } else {
2765 while (cur->next != NULL) cur = cur->next;
2766 cur->next = tmp;
2767 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002768 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002769 return (0);
2770}
2771
2772/**
2773 * xmlACatalogResolveSystem:
2774 * @catal: a Catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002775 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002776 *
2777 * Try to lookup the catalog resource for a system ID
2778 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002779 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002780 * must be freed by the caller.
2781 */
2782xmlChar *
2783xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2784 xmlChar *ret = NULL;
2785
2786 if ((sysID == NULL) || (catal == NULL))
2787 return(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002788
Daniel Veillard75b96822001-10-11 18:59:45 +00002789 if (xmlDebugCatalogs)
2790 xmlGenericError(xmlGenericErrorContext,
2791 "Resolve sysID %s\n", sysID);
2792
2793 if (catal->type == XML_XML_CATALOG_TYPE) {
2794 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2795 if (ret == XML_CATAL_BREAK)
2796 ret = NULL;
2797 } else {
2798 const xmlChar *sgml;
2799
2800 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2801 if (sgml != NULL)
2802 ret = xmlStrdup(sgml);
2803 }
2804 return(ret);
2805}
2806
2807/**
2808 * xmlACatalogResolvePublic:
2809 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002810 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002811 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002812 * Try to lookup the catalog local reference associated to a public ID in that catalog
Daniel Veillard75b96822001-10-11 18:59:45 +00002813 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002814 * Returns the local resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002815 * must be freed by the caller.
2816 */
2817xmlChar *
2818xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2819 xmlChar *ret = NULL;
2820
2821 if ((pubID == NULL) || (catal == NULL))
2822 return(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002823
Daniel Veillard75b96822001-10-11 18:59:45 +00002824 if (xmlDebugCatalogs)
2825 xmlGenericError(xmlGenericErrorContext,
2826 "Resolve pubID %s\n", pubID);
2827
2828 if (catal->type == XML_XML_CATALOG_TYPE) {
2829 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2830 if (ret == XML_CATAL_BREAK)
2831 ret = NULL;
2832 } else {
2833 const xmlChar *sgml;
2834
2835 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2836 if (sgml != NULL)
2837 ret = xmlStrdup(sgml);
2838 }
2839 return(ret);
2840}
2841
2842/**
2843 * xmlACatalogResolve:
2844 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002845 * @pubID: the public ID string
2846 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002847 *
2848 * Do a complete resolution lookup of an External Identifier
2849 *
2850 * Returns the URI of the resource or NULL if not found, it must be freed
2851 * by the caller.
2852 */
2853xmlChar *
2854xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2855 const xmlChar * sysID)
2856{
2857 xmlChar *ret = NULL;
2858
2859 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2860 return (NULL);
2861
2862 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002863 if ((pubID != NULL) && (sysID != NULL)) {
2864 xmlGenericError(xmlGenericErrorContext,
2865 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2866 } else if (pubID != NULL) {
2867 xmlGenericError(xmlGenericErrorContext,
2868 "Resolve: pubID %s\n", pubID);
2869 } else {
2870 xmlGenericError(xmlGenericErrorContext,
2871 "Resolve: sysID %s\n", sysID);
2872 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002873 }
2874
2875 if (catal->type == XML_XML_CATALOG_TYPE) {
2876 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2877 if (ret == XML_CATAL_BREAK)
2878 ret = NULL;
2879 } else {
2880 const xmlChar *sgml;
2881
2882 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2883 if (sgml != NULL)
2884 ret = xmlStrdup(sgml);
2885 }
2886 return (ret);
2887}
2888
2889/**
2890 * xmlACatalogResolveURI:
2891 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002892 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002893 *
2894 * Do a complete resolution lookup of an URI
2895 *
2896 * Returns the URI of the resource or NULL if not found, it must be freed
2897 * by the caller.
2898 */
2899xmlChar *
2900xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2901 xmlChar *ret = NULL;
2902
2903 if ((URI == NULL) || (catal == NULL))
2904 return(NULL);
2905
Daniel Veillardb44025c2001-10-11 22:55:55 +00002906 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002907 xmlGenericError(xmlGenericErrorContext,
2908 "Resolve URI %s\n", URI);
2909
2910 if (catal->type == XML_XML_CATALOG_TYPE) {
2911 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2912 if (ret == XML_CATAL_BREAK)
2913 ret = NULL;
2914 } else {
2915 const xmlChar *sgml;
2916
2917 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2918 if (sgml != NULL)
Daniel Veillard63806b52008-06-10 14:56:11 +00002919 ret = xmlStrdup(sgml);
Daniel Veillard75b96822001-10-11 18:59:45 +00002920 }
2921 return(ret);
2922}
2923
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002924#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002925/**
2926 * xmlACatalogDump:
2927 * @catal: a Catalog
2928 * @out: the file.
2929 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00002930 * Dump the given catalog to the given file.
Daniel Veillard75b96822001-10-11 18:59:45 +00002931 */
2932void
2933xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002934 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002935 return;
2936
2937 if (catal->type == XML_XML_CATALOG_TYPE) {
2938 xmlDumpXMLCatalog(out, catal->xml);
2939 } else {
2940 xmlHashScan(catal->sgml,
2941 (xmlHashScanner) xmlCatalogDumpEntry, out);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002942 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002943}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002944#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002945
2946/**
2947 * xmlACatalogAdd:
2948 * @catal: a Catalog
2949 * @type: the type of record to add to the catalog
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002950 * @orig: the system, public or prefix to match
Daniel Veillard75b96822001-10-11 18:59:45 +00002951 * @replace: the replacement value for the match
2952 *
2953 * Add an entry in the catalog, it may overwrite existing but
2954 * different entries.
2955 *
2956 * Returns 0 if successful, -1 otherwise
2957 */
2958int
2959xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2960 const xmlChar * orig, const xmlChar * replace)
2961{
2962 int res = -1;
2963
2964 if (catal == NULL)
2965 return(-1);
2966
2967 if (catal->type == XML_XML_CATALOG_TYPE) {
2968 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2969 } else {
2970 xmlCatalogEntryType cattype;
2971
2972 cattype = xmlGetSGMLCatalogEntryType(type);
2973 if (cattype != XML_CATA_NONE) {
2974 xmlCatalogEntryPtr entry;
2975
Daniel Veillardc853b322001-11-06 15:24:37 +00002976 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002977 XML_CATA_PREFER_NONE, NULL);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002978 if (catal->sgml == NULL)
2979 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002980 res = xmlHashAddEntry(catal->sgml, orig, entry);
2981 }
2982 }
2983 return (res);
2984}
2985
2986/**
2987 * xmlACatalogRemove:
2988 * @catal: a Catalog
2989 * @value: the value to remove
2990 *
2991 * Remove an entry from the catalog
2992 *
2993 * Returns the number of entries removed if successful, -1 otherwise
2994 */
2995int
2996xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2997 int res = -1;
2998
2999 if ((catal == NULL) || (value == NULL))
3000 return(-1);
3001
3002 if (catal->type == XML_XML_CATALOG_TYPE) {
3003 res = xmlDelXMLCatalog(catal->xml, value);
3004 } else {
3005 res = xmlHashRemoveEntry(catal->sgml, value,
3006 (xmlHashDeallocator) xmlFreeCatalogEntry);
3007 if (res == 0)
3008 res = 1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003009 }
Daniel Veillard75b96822001-10-11 18:59:45 +00003010 return(res);
3011}
3012
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003013/**
3014 * xmlNewCatalog:
3015 * @sgml: should this create an SGML catalog
3016 *
3017 * create a new Catalog.
3018 *
3019 * Returns the xmlCatalogPtr or NULL in case of error
3020 */
3021xmlCatalogPtr
3022xmlNewCatalog(int sgml) {
3023 xmlCatalogPtr catal = NULL;
3024
3025 if (sgml) {
3026 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
3027 xmlCatalogDefaultPrefer);
3028 if ((catal != NULL) && (catal->sgml == NULL))
3029 catal->sgml = xmlHashCreate(10);
3030 } else
3031 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3032 xmlCatalogDefaultPrefer);
3033 return(catal);
3034}
3035
3036/**
3037 * xmlCatalogIsEmpty:
3038 * @catal: should this create an SGML catalog
3039 *
3040 * Check is a catalog is empty
3041 *
3042 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3043 */
3044int
3045xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3046 if (catal == NULL)
3047 return(-1);
3048
3049 if (catal->type == XML_XML_CATALOG_TYPE) {
3050 if (catal->xml == NULL)
3051 return(1);
3052 if ((catal->xml->type != XML_CATA_CATALOG) &&
3053 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3054 return(-1);
3055 if (catal->xml->children == NULL)
3056 return(1);
3057 return(0);
3058 } else {
3059 int res;
3060
3061 if (catal->sgml == NULL)
3062 return(1);
3063 res = xmlHashSize(catal->sgml);
3064 if (res == 0)
3065 return(1);
3066 if (res < 0)
3067 return(-1);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003068 }
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003069 return(0);
3070}
3071
Daniel Veillard75b96822001-10-11 18:59:45 +00003072/************************************************************************
3073 * *
3074 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00003075 * *
3076 ************************************************************************/
3077
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003078/**
Daniel Veillard81463942001-10-16 12:34:39 +00003079 * xmlInitializeCatalogData:
3080 *
3081 * Do the catalog initialization only of global data, doesn't try to load
3082 * any catalog actually.
3083 * this function is not thread safe, catalog initialization should
3084 * preferably be done once at startup
3085 */
3086static void
3087xmlInitializeCatalogData(void) {
3088 if (xmlCatalogInitialized != 0)
3089 return;
3090
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003091 if (getenv("XML_DEBUG_CATALOG"))
Daniel Veillard81463942001-10-16 12:34:39 +00003092 xmlDebugCatalogs = 1;
3093 xmlCatalogMutex = xmlNewRMutex();
3094
3095 xmlCatalogInitialized = 1;
3096}
3097/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003098 * xmlInitializeCatalog:
3099 *
3100 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00003101 * this function is not thread safe, catalog initialization should
3102 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003103 */
3104void
3105xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003106 if (xmlCatalogInitialized != 0)
3107 return;
3108
Daniel Veillard81463942001-10-16 12:34:39 +00003109 xmlInitializeCatalogData();
3110 xmlRMutexLock(xmlCatalogMutex);
3111
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003112 if (getenv("XML_DEBUG_CATALOG"))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003113 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00003114
Daniel Veillard75b96822001-10-11 18:59:45 +00003115 if (xmlDefaultCatalog == NULL) {
3116 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003117 char *path;
3118 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00003119 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003120 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00003121
Daniel Veillardb44025c2001-10-11 22:55:55 +00003122 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003123 if (catalogs == NULL)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003124#if defined(_WIN32) && defined(_MSC_VER)
3125 {
3126 void* hmodule;
3127 hmodule = GetModuleHandleA("libxml2.dll");
3128 if (hmodule == NULL)
3129 hmodule = GetModuleHandleA(NULL);
3130 if (hmodule != NULL) {
3131 char buf[256];
3132 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3133 if (len != 0) {
3134 char* p = &(buf[len]);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003135 while (*p != '\\' && p > buf)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003136 p--;
3137 if (p != buf) {
3138 xmlChar* uri;
3139 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
Denis Pauke1631e12013-03-10 12:47:37 +02003140 uri = xmlCanonicPath((const xmlChar*)buf);
Daniel Veillardfb382b82004-06-14 12:13:12 +00003141 if (uri != NULL) {
3142 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3143 xmlFree(uri);
3144 }
3145 }
3146 }
3147 }
3148 catalogs = XML_XML_DEFAULT_CATALOG;
3149 }
3150#else
Daniel Veillard75b96822001-10-11 18:59:45 +00003151 catalogs = XML_XML_DEFAULT_CATALOG;
Daniel Veillardfb382b82004-06-14 12:13:12 +00003152#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00003153
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003154 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003155 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003156 if (catal != NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003157 /* the XML_CATALOG_FILES envvar is allowed to contain a
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003158 space-separated list of entries. */
3159 cur = catalogs;
3160 nextent = &catal->xml;
3161 while (*cur != '\0') {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003162 while (xmlIsBlank_ch(*cur))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003163 cur++;
3164 if (*cur != 0) {
3165 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003166 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003167 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00003168 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003169 if (path != NULL) {
3170 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003171 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003172 if (*nextent != NULL)
3173 nextent = &((*nextent)->next);
3174 xmlFree(path);
3175 }
3176 }
3177 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003178 xmlDefaultCatalog = catal;
3179 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003180 }
3181
Daniel Veillard81463942001-10-16 12:34:39 +00003182 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003183}
3184
Daniel Veillard82d75332001-10-08 15:01:59 +00003185
3186/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003187 * xmlLoadCatalog:
3188 * @filename: a file path
3189 *
Daniel Veillard81418e32001-05-22 15:08:55 +00003190 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003191 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00003192 * this function is not thread safe, catalog initialization should
3193 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00003194 *
3195 * Returns 0 in case of success -1 in case of error
3196 */
3197int
Daniel Veillard16756b62001-10-01 07:36:25 +00003198xmlLoadCatalog(const char *filename)
3199{
Daniel Veillard75b96822001-10-11 18:59:45 +00003200 int ret;
3201 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00003202
Daniel Veillard81463942001-10-16 12:34:39 +00003203 if (!xmlCatalogInitialized)
3204 xmlInitializeCatalogData();
3205
3206 xmlRMutexLock(xmlCatalogMutex);
3207
Daniel Veillard75b96822001-10-11 18:59:45 +00003208 if (xmlDefaultCatalog == NULL) {
3209 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00003210 if (catal == NULL) {
3211 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003212 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00003213 }
Daniel Veillarda7374592001-05-10 14:17:55 +00003214
Daniel Veillard75b96822001-10-11 18:59:45 +00003215 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00003216 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003217 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003218 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003219
Daniel Veillard75b96822001-10-11 18:59:45 +00003220 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00003221 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003222 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003223}
3224
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003225/**
Daniel Veillard81418e32001-05-22 15:08:55 +00003226 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003227 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003228 *
3229 * Load the catalogs and makes their definitions effective for the default
3230 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003231 * this function is not thread safe, catalog initialization should
3232 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003233 */
3234void
3235xmlLoadCatalogs(const char *pathss) {
3236 const char *cur;
3237 const char *paths;
3238 xmlChar *path;
Daniel Veillarded121382007-04-17 12:33:19 +00003239#ifdef _WIN32
3240 int i, iLen;
3241#endif
Daniel Veillard81418e32001-05-22 15:08:55 +00003242
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003243 if (pathss == NULL)
3244 return;
3245
Daniel Veillard81418e32001-05-22 15:08:55 +00003246 cur = pathss;
Daniel Veillard2728f842006-03-09 16:49:24 +00003247 while (*cur != 0) {
William M. Brack68aca052003-10-11 15:22:13 +00003248 while (xmlIsBlank_ch(*cur)) cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003249 if (*cur != 0) {
3250 paths = cur;
Jan Pokorný9811ce72016-04-13 16:56:06 +02003251 while ((*cur != 0) && (*cur != PATH_SEPARATOR) && (!xmlIsBlank_ch(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003252 cur++;
3253 path = xmlStrndup((const xmlChar *)paths, cur - paths);
Daniel Veillarded121382007-04-17 12:33:19 +00003254#ifdef _WIN32
Denis Pauke1631e12013-03-10 12:47:37 +02003255 iLen = strlen((const char*)path);
Daniel Veillarded121382007-04-17 12:33:19 +00003256 for(i = 0; i < iLen; i++) {
3257 if(path[i] == '\\') {
3258 path[i] = '/';
3259 }
3260 }
3261#endif
Daniel Veillard81418e32001-05-22 15:08:55 +00003262 if (path != NULL) {
3263 xmlLoadCatalog((const char *) path);
3264 xmlFree(path);
3265 }
3266 }
Jan Pokorný9811ce72016-04-13 16:56:06 +02003267 while (*cur == PATH_SEPARATOR)
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003268 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003269 }
3270}
3271
Daniel Veillarda7374592001-05-10 14:17:55 +00003272/**
3273 * xmlCatalogCleanup:
3274 *
3275 * Free up all the memory associated with catalogs
3276 */
3277void
3278xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003279 if (xmlCatalogInitialized == 0)
3280 return;
3281
Daniel Veillard81463942001-10-16 12:34:39 +00003282 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003283 if (xmlDebugCatalogs)
3284 xmlGenericError(xmlGenericErrorContext,
3285 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003286 if (xmlCatalogXMLFiles != NULL)
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003287 xmlHashFree(xmlCatalogXMLFiles,
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003288 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003289 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003290 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003291 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003292 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003293 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003294 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003295 xmlRMutexUnlock(xmlCatalogMutex);
3296 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003297}
3298
3299/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003300 * xmlCatalogResolveSystem:
Daniel Veillard06d25242004-02-25 13:01:42 +00003301 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003302 *
3303 * Try to lookup the catalog resource for a system ID
3304 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003305 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003306 * must be freed by the caller.
3307 */
3308xmlChar *
3309xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003310 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003311
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003312 if (!xmlCatalogInitialized)
3313 xmlInitializeCatalog();
3314
Daniel Veillard75b96822001-10-11 18:59:45 +00003315 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3316 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003317}
3318
3319/**
3320 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003321 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003322 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003323 * Try to lookup the catalog reference associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003324 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003325 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003326 * must be freed by the caller.
3327 */
3328xmlChar *
3329xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003330 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003331
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003332 if (!xmlCatalogInitialized)
3333 xmlInitializeCatalog();
3334
Daniel Veillard75b96822001-10-11 18:59:45 +00003335 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3336 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003337}
Daniel Veillard344cee72001-08-20 00:08:40 +00003338
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003339/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003340 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003341 * @pubID: the public ID string
3342 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003343 *
3344 * Do a complete resolution lookup of an External Identifier
3345 *
3346 * Returns the URI of the resource or NULL if not found, it must be freed
3347 * by the caller.
3348 */
3349xmlChar *
3350xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003351 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003352
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003353 if (!xmlCatalogInitialized)
3354 xmlInitializeCatalog();
3355
Daniel Veillard75b96822001-10-11 18:59:45 +00003356 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3357 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003358}
3359
3360/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003361 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003362 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003363 *
3364 * Do a complete resolution lookup of an URI
3365 *
3366 * Returns the URI of the resource or NULL if not found, it must be freed
3367 * by the caller.
3368 */
3369xmlChar *
3370xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003371 xmlChar *ret;
3372
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003373 if (!xmlCatalogInitialized)
3374 xmlInitializeCatalog();
3375
Daniel Veillard75b96822001-10-11 18:59:45 +00003376 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3377 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003378}
3379
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003380#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003381/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003382 * xmlCatalogDump:
3383 * @out: the file.
3384 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00003385 * Dump all the global catalog content to the given file.
Daniel Veillarda7374592001-05-10 14:17:55 +00003386 */
3387void
3388xmlCatalogDump(FILE *out) {
3389 if (out == NULL)
3390 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003391
Daniel Veillard75b96822001-10-11 18:59:45 +00003392 if (!xmlCatalogInitialized)
3393 xmlInitializeCatalog();
3394
3395 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003396}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003397#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003398
3399/**
3400 * xmlCatalogAdd:
3401 * @type: the type of record to add to the catalog
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003402 * @orig: the system, public or prefix to match
Daniel Veillard344cee72001-08-20 00:08:40 +00003403 * @replace: the replacement value for the match
3404 *
3405 * Add an entry in the catalog, it may overwrite existing but
3406 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003407 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003408 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003409 *
3410 * Returns 0 if successful, -1 otherwise
3411 */
3412int
3413xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3414 int res = -1;
3415
Daniel Veillard81463942001-10-16 12:34:39 +00003416 if (!xmlCatalogInitialized)
3417 xmlInitializeCatalogData();
3418
3419 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003420 /*
3421 * Specific case where one want to override the default catalog
3422 * put in place by xmlInitializeCatalog();
3423 */
3424 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003425 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003426 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003427 xmlCatalogDefaultPrefer);
3428 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003429 orig, NULL, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003430
Daniel Veillard81463942001-10-16 12:34:39 +00003431 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003432 return(0);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003433 }
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003434
Daniel Veillard75b96822001-10-11 18:59:45 +00003435 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003436 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003437 return(res);
3438}
3439
3440/**
3441 * xmlCatalogRemove:
3442 * @value: the value to remove
3443 *
3444 * Remove an entry from the catalog
3445 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003446 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003447 */
3448int
3449xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003450 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003451
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003452 if (!xmlCatalogInitialized)
3453 xmlInitializeCatalog();
3454
Daniel Veillard81463942001-10-16 12:34:39 +00003455 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003456 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003457 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003458 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003459}
3460
3461/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003462 * xmlCatalogConvert:
3463 *
3464 * Convert all the SGML catalog entries as XML ones
3465 *
3466 * Returns the number of entries converted if successful, -1 otherwise
3467 */
3468int
3469xmlCatalogConvert(void) {
3470 int res = -1;
3471
3472 if (!xmlCatalogInitialized)
3473 xmlInitializeCatalog();
3474
Daniel Veillard81463942001-10-16 12:34:39 +00003475 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003476 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003477 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003478 return(res);
3479}
3480
Daniel Veillard75b96822001-10-11 18:59:45 +00003481/************************************************************************
3482 * *
3483 * Public interface manipulating the common preferences *
3484 * *
3485 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003486
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003487/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003488 * xmlCatalogGetDefaults:
3489 *
3490 * Used to get the user preference w.r.t. to what catalogs should
3491 * be accepted
3492 *
3493 * Returns the current xmlCatalogAllow value
3494 */
3495xmlCatalogAllow
3496xmlCatalogGetDefaults(void) {
3497 return(xmlCatalogDefaultAllow);
3498}
3499
3500/**
3501 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003502 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003503 *
3504 * Used to set the user preference w.r.t. to what catalogs should
3505 * be accepted
3506 */
3507void
3508xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003509 if (xmlDebugCatalogs) {
3510 switch (allow) {
3511 case XML_CATA_ALLOW_NONE:
3512 xmlGenericError(xmlGenericErrorContext,
3513 "Disabling catalog usage\n");
3514 break;
3515 case XML_CATA_ALLOW_GLOBAL:
3516 xmlGenericError(xmlGenericErrorContext,
3517 "Allowing only global catalogs\n");
3518 break;
3519 case XML_CATA_ALLOW_DOCUMENT:
3520 xmlGenericError(xmlGenericErrorContext,
3521 "Allowing only catalogs from the document\n");
3522 break;
3523 case XML_CATA_ALLOW_ALL:
3524 xmlGenericError(xmlGenericErrorContext,
3525 "Allowing all catalogs\n");
3526 break;
3527 }
3528 }
3529 xmlCatalogDefaultAllow = allow;
3530}
3531
3532/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003533 * xmlCatalogSetDefaultPrefer:
3534 * @prefer: the default preference for delegation
3535 *
3536 * Allows to set the preference between public and system for deletion
3537 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003538 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003539 *
3540 * Returns the previous value of the default preference for delegation
3541 */
3542xmlCatalogPrefer
3543xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3544 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3545
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003546 if (prefer == XML_CATA_PREFER_NONE)
3547 return(ret);
3548
3549 if (xmlDebugCatalogs) {
3550 switch (prefer) {
3551 case XML_CATA_PREFER_PUBLIC:
3552 xmlGenericError(xmlGenericErrorContext,
3553 "Setting catalog preference to PUBLIC\n");
3554 break;
3555 case XML_CATA_PREFER_SYSTEM:
3556 xmlGenericError(xmlGenericErrorContext,
3557 "Setting catalog preference to SYSTEM\n");
3558 break;
Daniel Veillardb8bdc252013-09-30 11:12:04 +08003559 default:
3560 return(ret);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003561 }
3562 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003563 xmlCatalogDefaultPrefer = prefer;
3564 return(ret);
3565}
3566
3567/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003568 * xmlCatalogSetDebug:
3569 * @level: the debug level of catalogs required
3570 *
3571 * Used to set the debug level for catalog operation, 0 disable
3572 * debugging, 1 enable it
3573 *
3574 * Returns the previous value of the catalog debugging level
3575 */
3576int
3577xmlCatalogSetDebug(int level) {
3578 int ret = xmlDebugCatalogs;
3579
3580 if (level <= 0)
3581 xmlDebugCatalogs = 0;
3582 else
3583 xmlDebugCatalogs = level;
3584 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003585}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003586
Daniel Veillard75b96822001-10-11 18:59:45 +00003587/************************************************************************
3588 * *
3589 * Minimal interfaces used for per-document catalogs by the parser *
3590 * *
3591 ************************************************************************/
3592
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003593/**
3594 * xmlCatalogFreeLocal:
3595 * @catalogs: a document's list of catalogs
3596 *
3597 * Free up the memory associated to the catalog list
3598 */
3599void
3600xmlCatalogFreeLocal(void *catalogs) {
3601 xmlCatalogEntryPtr catal;
3602
Daniel Veillard81463942001-10-16 12:34:39 +00003603 if (!xmlCatalogInitialized)
3604 xmlInitializeCatalog();
3605
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003606 catal = (xmlCatalogEntryPtr) catalogs;
3607 if (catal != NULL)
3608 xmlFreeCatalogEntryList(catal);
3609}
3610
3611
3612/**
3613 * xmlCatalogAddLocal:
3614 * @catalogs: a document's list of catalogs
3615 * @URL: the URL to a new local catalog
3616 *
3617 * Add the new entry to the catalog list
3618 *
3619 * Returns the updated list
3620 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003621void *
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003622xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3623 xmlCatalogEntryPtr catal, add;
3624
3625 if (!xmlCatalogInitialized)
3626 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003627
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003628 if (URL == NULL)
3629 return(catalogs);
3630
3631 if (xmlDebugCatalogs)
3632 xmlGenericError(xmlGenericErrorContext,
3633 "Adding document catalog %s\n", URL);
3634
Daniel Veillardc853b322001-11-06 15:24:37 +00003635 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003636 xmlCatalogDefaultPrefer, NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003637 if (add == NULL)
3638 return(catalogs);
3639
3640 catal = (xmlCatalogEntryPtr) catalogs;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003641 if (catal == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003642 return((void *) add);
3643
3644 while (catal->next != NULL)
3645 catal = catal->next;
3646 catal->next = add;
3647 return(catalogs);
3648}
3649
3650/**
3651 * xmlCatalogLocalResolve:
3652 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003653 * @pubID: the public ID string
3654 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003655 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003656 * Do a complete resolution lookup of an External Identifier using a
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003657 * document's private catalog list
3658 *
3659 * Returns the URI of the resource or NULL if not found, it must be freed
3660 * by the caller.
3661 */
3662xmlChar *
3663xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3664 const xmlChar *sysID) {
3665 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003666 xmlChar *ret;
3667
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003668 if (!xmlCatalogInitialized)
3669 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003670
Daniel Veillard81463942001-10-16 12:34:39 +00003671 if ((pubID == NULL) && (sysID == NULL))
3672 return(NULL);
3673
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003674 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003675 if ((pubID != NULL) && (sysID != NULL)) {
3676 xmlGenericError(xmlGenericErrorContext,
3677 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3678 } else if (pubID != NULL) {
3679 xmlGenericError(xmlGenericErrorContext,
3680 "Local Resolve: pubID %s\n", pubID);
3681 } else {
3682 xmlGenericError(xmlGenericErrorContext,
3683 "Local Resolve: sysID %s\n", sysID);
3684 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003685 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003686
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003687 catal = (xmlCatalogEntryPtr) catalogs;
3688 if (catal == NULL)
3689 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003690 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3691 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3692 return(ret);
3693 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003694}
3695
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003696/**
3697 * xmlCatalogLocalResolveURI:
3698 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003699 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003700 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003701 * Do a complete resolution lookup of an URI using a
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003702 * document's private catalog list
3703 *
3704 * Returns the URI of the resource or NULL if not found, it must be freed
3705 * by the caller.
3706 */
3707xmlChar *
3708xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3709 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003710 xmlChar *ret;
3711
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003712 if (!xmlCatalogInitialized)
3713 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003714
Daniel Veillard81463942001-10-16 12:34:39 +00003715 if (URI == NULL)
3716 return(NULL);
3717
Daniel Veillard6990bf32001-08-23 21:17:48 +00003718 if (xmlDebugCatalogs)
3719 xmlGenericError(xmlGenericErrorContext,
3720 "Resolve URI %s\n", URI);
3721
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003722 catal = (xmlCatalogEntryPtr) catalogs;
3723 if (catal == NULL)
3724 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003725 ret = xmlCatalogListXMLResolveURI(catal, URI);
3726 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3727 return(ret);
3728 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003729}
3730
Daniel Veillard75b96822001-10-11 18:59:45 +00003731/************************************************************************
3732 * *
3733 * Deprecated interfaces *
3734 * *
3735 ************************************************************************/
3736/**
3737 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003738 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003739 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003740 * Try to lookup the catalog reference associated to a system ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003741 * DEPRECATED, use xmlCatalogResolveSystem()
3742 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003743 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003744 */
3745const xmlChar *
3746xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003747 xmlChar *ret;
3748 static xmlChar result[1000];
3749 static int msg = 0;
3750
3751 if (!xmlCatalogInitialized)
3752 xmlInitializeCatalog();
3753
3754 if (msg == 0) {
3755 xmlGenericError(xmlGenericErrorContext,
3756 "Use of deprecated xmlCatalogGetSystem() call\n");
3757 msg++;
3758 }
3759
3760 if (sysID == NULL)
3761 return(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003762
Daniel Veillardab690c52004-06-14 12:19:09 +00003763 /*
3764 * Check first the XML catalogs
3765 */
3766 if (xmlDefaultCatalog != NULL) {
3767 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3768 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3769 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3770 result[sizeof(result) - 1] = 0;
3771 return(result);
3772 }
3773 }
3774
3775 if (xmlDefaultCatalog != NULL)
3776 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3777 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003778}
3779
3780/**
3781 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003782 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003783 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003784 * Try to lookup the catalog reference associated to a public ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003785 * DEPRECATED, use xmlCatalogResolvePublic()
3786 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003787 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003788 */
3789const xmlChar *
3790xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003791 xmlChar *ret;
3792 static xmlChar result[1000];
3793 static int msg = 0;
3794
3795 if (!xmlCatalogInitialized)
3796 xmlInitializeCatalog();
3797
3798 if (msg == 0) {
3799 xmlGenericError(xmlGenericErrorContext,
3800 "Use of deprecated xmlCatalogGetPublic() call\n");
3801 msg++;
3802 }
3803
3804 if (pubID == NULL)
3805 return(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003806
Daniel Veillardab690c52004-06-14 12:19:09 +00003807 /*
3808 * Check first the XML catalogs
3809 */
3810 if (xmlDefaultCatalog != NULL) {
3811 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3812 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3813 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3814 result[sizeof(result) - 1] = 0;
3815 return(result);
3816 }
3817 }
3818
3819 if (xmlDefaultCatalog != NULL)
3820 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3821 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003822}
3823
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003824#define bottom_catalog
3825#include "elfgcchack.h"
Daniel Veillarda7374592001-05-10 14:17:55 +00003826#endif /* LIBXML_CATALOG_ENABLED */