blob: f814121ce82aca5d25a83fefd14f825c6bed65c5 [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:
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100322 * @payload: a Catalog entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000323 *
324 * Free the memory allocated to a Catalog entry
325 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000326static void
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100327xmlFreeCatalogEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
328 xmlCatalogEntryPtr ret = (xmlCatalogEntryPtr) payload;
Daniel Veillarda7374592001-05-10 14:17:55 +0000329 if (ret == NULL)
330 return;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000331 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000332 * Entries stored in the file hash must be deallocated
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000333 * only by the file hash cleaner !
334 */
335 if (ret->dealloc == 1)
336 return;
337
338 if (xmlDebugCatalogs) {
339 if (ret->name != NULL)
340 xmlGenericError(xmlGenericErrorContext,
341 "Free catalog entry %s\n", ret->name);
342 else if (ret->value != NULL)
343 xmlGenericError(xmlGenericErrorContext,
344 "Free catalog entry %s\n", ret->value);
345 else
346 xmlGenericError(xmlGenericErrorContext,
347 "Free catalog entry\n");
348 }
349
Daniel Veillarda7374592001-05-10 14:17:55 +0000350 if (ret->name != NULL)
351 xmlFree(ret->name);
352 if (ret->value != NULL)
353 xmlFree(ret->value);
Daniel Veillardc853b322001-11-06 15:24:37 +0000354 if (ret->URL != NULL)
355 xmlFree(ret->URL);
Daniel Veillarda7374592001-05-10 14:17:55 +0000356 xmlFree(ret);
357}
358
Daniel Veillard75b96822001-10-11 18:59:45 +0000359/**
360 * xmlFreeCatalogEntryList:
361 * @ret: a Catalog entry list
362 *
363 * Free the memory allocated to a full chained list of Catalog entries
364 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000365static void
366xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
367 xmlCatalogEntryPtr next;
368
369 while (ret != NULL) {
370 next = ret->next;
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100371 xmlFreeCatalogEntry(ret, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +0000372 ret = next;
373 }
374}
375
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000376/**
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000377 * xmlFreeCatalogHashEntryList:
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100378 * @payload: a Catalog entry list
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000379 *
380 * Free the memory allocated to list of Catalog entries from the
381 * catalog file hash.
382 */
383static void
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100384xmlFreeCatalogHashEntryList(void *payload,
385 const xmlChar *name ATTRIBUTE_UNUSED) {
386 xmlCatalogEntryPtr catal = (xmlCatalogEntryPtr) payload;
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000387 xmlCatalogEntryPtr children, next;
388
389 if (catal == NULL)
390 return;
391
392 children = catal->children;
393 while (children != NULL) {
394 next = children->next;
395 children->dealloc = 0;
396 children->children = NULL;
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100397 xmlFreeCatalogEntry(children, NULL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000398 children = next;
399 }
400 catal->dealloc = 0;
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100401 xmlFreeCatalogEntry(catal, NULL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +0000402}
403
404/**
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000405 * xmlCreateNewCatalog:
Daniel Veillard75b96822001-10-11 18:59:45 +0000406 * @type: type of catalog
407 * @prefer: the PUBLIC vs. SYSTEM current preference value
408 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800409 * create a new Catalog, this type is shared both by XML and
Daniel Veillard75b96822001-10-11 18:59:45 +0000410 * SGML catalogs, but the acceptable types values differs.
411 *
412 * Returns the xmlCatalogPtr or NULL in case of error
413 */
414static xmlCatalogPtr
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000415xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
Daniel Veillard75b96822001-10-11 18:59:45 +0000416 xmlCatalogPtr ret;
417
418 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
419 if (ret == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +0000420 xmlCatalogErrMemory("allocating catalog");
Daniel Veillard75b96822001-10-11 18:59:45 +0000421 return(NULL);
422 }
423 memset(ret, 0, sizeof(xmlCatalog));
424 ret->type = type;
425 ret->catalNr = 0;
426 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
427 ret->prefer = prefer;
Daniel Veillardcd21dc72001-11-04 20:03:38 +0000428 if (ret->type == XML_SGML_CATALOG_TYPE)
429 ret->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +0000430 return(ret);
431}
432
433/**
434 * xmlFreeCatalog:
Daniel Veillard06d25242004-02-25 13:01:42 +0000435 * @catal: a Catalog
Daniel Veillard75b96822001-10-11 18:59:45 +0000436 *
437 * Free the memory allocated to a Catalog
438 */
439void
440xmlFreeCatalog(xmlCatalogPtr catal) {
441 if (catal == NULL)
442 return;
443 if (catal->xml != NULL)
444 xmlFreeCatalogEntryList(catal->xml);
445 if (catal->sgml != NULL)
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100446 xmlHashFree(catal->sgml, xmlFreeCatalogEntry);
Daniel Veillard75b96822001-10-11 18:59:45 +0000447 xmlFree(catal);
448}
449
450/************************************************************************
451 * *
452 * Serializing Catalogs *
453 * *
454 ************************************************************************/
455
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000456#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +0000457/**
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000458 * xmlCatalogDumpEntry:
Daniel Veillard06d25242004-02-25 13:01:42 +0000459 * @entry: the catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000460 * @out: the file.
461 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000462 * Serialize an SGML Catalog entry
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000463 */
464static void
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100465xmlCatalogDumpEntry(void *payload, void *data,
466 const xmlChar *name ATTRIBUTE_UNUSED) {
467 xmlCatalogEntryPtr entry = (xmlCatalogEntryPtr) payload;
468 FILE *out = (FILE *) data;
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000469 if ((entry == NULL) || (out == NULL))
470 return;
471 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000472 case SGML_CATA_ENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000473 fprintf(out, "ENTITY "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000474 case SGML_CATA_PENTITY:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000475 fprintf(out, "ENTITY %%"); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000476 case SGML_CATA_DOCTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000477 fprintf(out, "DOCTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000478 case SGML_CATA_LINKTYPE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000479 fprintf(out, "LINKTYPE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000480 case SGML_CATA_NOTATION:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000481 fprintf(out, "NOTATION "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000482 case SGML_CATA_PUBLIC:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000483 fprintf(out, "PUBLIC "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000484 case SGML_CATA_SYSTEM:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000485 fprintf(out, "SYSTEM "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000486 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000487 fprintf(out, "DELEGATE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000488 case SGML_CATA_BASE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000489 fprintf(out, "BASE "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000490 case SGML_CATA_CATALOG:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000491 fprintf(out, "CATALOG "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000492 case SGML_CATA_DOCUMENT:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000493 fprintf(out, "DOCUMENT "); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000494 case SGML_CATA_SGMLDECL:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000495 fprintf(out, "SGMLDECL "); break;
496 default:
497 return;
498 }
499 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000500 case SGML_CATA_ENTITY:
501 case SGML_CATA_PENTITY:
502 case SGML_CATA_DOCTYPE:
503 case SGML_CATA_LINKTYPE:
504 case SGML_CATA_NOTATION:
Daniel Veillard580ced82003-03-21 21:22:48 +0000505 fprintf(out, "%s", (const char *) entry->name); break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000506 case SGML_CATA_PUBLIC:
507 case SGML_CATA_SYSTEM:
508 case SGML_CATA_SGMLDECL:
509 case SGML_CATA_DOCUMENT:
510 case SGML_CATA_CATALOG:
511 case SGML_CATA_BASE:
512 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000513 fprintf(out, "\"%s\"", entry->name); break;
514 default:
515 break;
516 }
517 switch (entry->type) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000518 case SGML_CATA_ENTITY:
519 case SGML_CATA_PENTITY:
520 case SGML_CATA_DOCTYPE:
521 case SGML_CATA_LINKTYPE:
522 case SGML_CATA_NOTATION:
523 case SGML_CATA_PUBLIC:
524 case SGML_CATA_SYSTEM:
525 case SGML_CATA_DELEGATE:
Daniel Veillard7d6fd212001-05-10 15:34:11 +0000526 fprintf(out, " \"%s\"", entry->value); break;
527 default:
528 break;
529 }
530 fprintf(out, "\n");
531}
532
William M. Brackb7b54de2004-10-06 16:38:01 +0000533/**
534 * xmlDumpXMLCatalogNode:
535 * @catal: top catalog entry
536 * @catalog: pointer to the xml tree
537 * @doc: the containing document
538 * @ns: the current namespace
539 * @cgroup: group node for group members
540 *
541 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
542 * for group entries
543 */
544static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
545 xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
546 xmlNodePtr node;
547 xmlCatalogEntryPtr cur;
548 /*
549 * add all the catalog entries
550 */
551 cur = catal;
552 while (cur != NULL) {
553 if (cur->group == cgroup) {
554 switch (cur->type) {
555 case XML_CATA_REMOVED:
556 break;
557 case XML_CATA_BROKEN_CATALOG:
558 case XML_CATA_CATALOG:
559 if (cur == catal) {
560 cur = cur->children;
561 continue;
562 }
563 break;
564 case XML_CATA_NEXT_CATALOG:
565 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
566 xmlSetProp(node, BAD_CAST "catalog", cur->value);
567 xmlAddChild(catalog, node);
568 break;
569 case XML_CATA_NONE:
570 break;
571 case XML_CATA_GROUP:
572 node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
573 xmlSetProp(node, BAD_CAST "id", cur->name);
William M. Brack6218b312004-10-06 17:52:32 +0000574 if (cur->value != NULL) {
575 xmlNsPtr xns;
576 xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
577 if (xns != NULL)
578 xmlSetNsProp(node, xns, BAD_CAST "base",
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800579 cur->value);
William M. Brack6218b312004-10-06 17:52:32 +0000580 }
William M. Brackb7b54de2004-10-06 16:38:01 +0000581 switch (cur->prefer) {
582 case XML_CATA_PREFER_NONE:
583 break;
584 case XML_CATA_PREFER_PUBLIC:
585 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
586 break;
587 case XML_CATA_PREFER_SYSTEM:
588 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
589 break;
590 }
591 xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
592 xmlAddChild(catalog, node);
593 break;
594 case XML_CATA_PUBLIC:
595 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
596 xmlSetProp(node, BAD_CAST "publicId", cur->name);
597 xmlSetProp(node, BAD_CAST "uri", cur->value);
598 xmlAddChild(catalog, node);
599 break;
600 case XML_CATA_SYSTEM:
601 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
602 xmlSetProp(node, BAD_CAST "systemId", cur->name);
603 xmlSetProp(node, BAD_CAST "uri", cur->value);
604 xmlAddChild(catalog, node);
605 break;
606 case XML_CATA_REWRITE_SYSTEM:
607 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
608 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
609 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
610 xmlAddChild(catalog, node);
611 break;
612 case XML_CATA_DELEGATE_PUBLIC:
613 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
614 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
615 xmlSetProp(node, BAD_CAST "catalog", cur->value);
616 xmlAddChild(catalog, node);
617 break;
618 case XML_CATA_DELEGATE_SYSTEM:
619 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
620 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
621 xmlSetProp(node, BAD_CAST "catalog", cur->value);
622 xmlAddChild(catalog, node);
623 break;
624 case XML_CATA_URI:
625 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
626 xmlSetProp(node, BAD_CAST "name", cur->name);
627 xmlSetProp(node, BAD_CAST "uri", cur->value);
628 xmlAddChild(catalog, node);
629 break;
630 case XML_CATA_REWRITE_URI:
631 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
632 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
633 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
634 xmlAddChild(catalog, node);
635 break;
636 case XML_CATA_DELEGATE_URI:
637 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
638 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
639 xmlSetProp(node, BAD_CAST "catalog", cur->value);
640 xmlAddChild(catalog, node);
641 break;
642 case SGML_CATA_SYSTEM:
643 case SGML_CATA_PUBLIC:
644 case SGML_CATA_ENTITY:
645 case SGML_CATA_PENTITY:
646 case SGML_CATA_DOCTYPE:
647 case SGML_CATA_LINKTYPE:
648 case SGML_CATA_NOTATION:
649 case SGML_CATA_DELEGATE:
650 case SGML_CATA_BASE:
651 case SGML_CATA_CATALOG:
652 case SGML_CATA_DOCUMENT:
653 case SGML_CATA_SGMLDECL:
654 break;
655 }
656 }
657 cur = cur->next;
658 }
659}
660
Daniel Veillard75b96822001-10-11 18:59:45 +0000661static int
662xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
663 int ret;
664 xmlDocPtr doc;
665 xmlNsPtr ns;
666 xmlDtdPtr dtd;
William M. Brackb7b54de2004-10-06 16:38:01 +0000667 xmlNodePtr catalog;
Daniel Veillard75b96822001-10-11 18:59:45 +0000668 xmlOutputBufferPtr buf;
Daniel Veillard75b96822001-10-11 18:59:45 +0000669
670 /*
671 * Rebuild a catalog
672 */
673 doc = xmlNewDoc(NULL);
674 if (doc == NULL)
675 return(-1);
676 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
677 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
678BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
679
680 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
681
682 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
683 if (ns == NULL) {
684 xmlFreeDoc(doc);
685 return(-1);
686 }
687 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
688 if (catalog == NULL) {
689 xmlFreeNs(ns);
690 xmlFreeDoc(doc);
691 return(-1);
692 }
693 catalog->nsDef = ns;
694 xmlAddChild((xmlNodePtr) doc, catalog);
695
William M. Brackb7b54de2004-10-06 16:38:01 +0000696 xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800697
Daniel Veillard75b96822001-10-11 18:59:45 +0000698 /*
699 * reserialize it
700 */
701 buf = xmlOutputBufferCreateFile(out, NULL);
702 if (buf == NULL) {
703 xmlFreeDoc(doc);
704 return(-1);
705 }
706 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
707
708 /*
709 * Free it
710 */
711 xmlFreeDoc(doc);
712
713 return(ret);
714}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000715#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +0000716
717/************************************************************************
718 * *
719 * Converting SGML Catalogs to XML *
720 * *
721 ************************************************************************/
722
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000723/**
724 * xmlCatalogConvertEntry:
725 * @entry: the entry
Daniel Veillard75b96822001-10-11 18:59:45 +0000726 * @catal: pointer to the catalog being converted
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000727 *
Daniel Veillard75b96822001-10-11 18:59:45 +0000728 * Convert one entry from the catalog
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000729 */
730static void
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100731xmlCatalogConvertEntry(void *payload, void *data,
732 const xmlChar *name ATTRIBUTE_UNUSED) {
733 xmlCatalogEntryPtr entry = (xmlCatalogEntryPtr) payload;
734 xmlCatalogPtr catal = (xmlCatalogPtr) data;
Daniel Veillard75b96822001-10-11 18:59:45 +0000735 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
736 (catal->xml == NULL))
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000737 return;
738 switch (entry->type) {
739 case SGML_CATA_ENTITY:
740 entry->type = XML_CATA_PUBLIC;
741 break;
742 case SGML_CATA_PENTITY:
743 entry->type = XML_CATA_PUBLIC;
744 break;
745 case SGML_CATA_DOCTYPE:
746 entry->type = XML_CATA_PUBLIC;
747 break;
748 case SGML_CATA_LINKTYPE:
749 entry->type = XML_CATA_PUBLIC;
750 break;
751 case SGML_CATA_NOTATION:
752 entry->type = XML_CATA_PUBLIC;
753 break;
754 case SGML_CATA_PUBLIC:
755 entry->type = XML_CATA_PUBLIC;
756 break;
757 case SGML_CATA_SYSTEM:
758 entry->type = XML_CATA_SYSTEM;
759 break;
760 case SGML_CATA_DELEGATE:
761 entry->type = XML_CATA_DELEGATE_PUBLIC;
762 break;
763 case SGML_CATA_CATALOG:
764 entry->type = XML_CATA_CATALOG;
765 break;
766 default:
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100767 xmlHashRemoveEntry(catal->sgml, entry->name, xmlFreeCatalogEntry);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000768 return;
769 }
770 /*
771 * Conversion successful, remove from the SGML catalog
772 * and add it to the default XML one
773 */
Daniel Veillard75b96822001-10-11 18:59:45 +0000774 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
775 entry->parent = catal->xml;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000776 entry->next = NULL;
Daniel Veillard75b96822001-10-11 18:59:45 +0000777 if (catal->xml->children == NULL)
778 catal->xml->children = entry;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000779 else {
780 xmlCatalogEntryPtr prev;
781
Daniel Veillard75b96822001-10-11 18:59:45 +0000782 prev = catal->xml->children;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000783 while (prev->next != NULL)
784 prev = prev->next;
785 prev->next = entry;
786 }
Daniel Veillard75b96822001-10-11 18:59:45 +0000787}
788
789/**
790 * xmlConvertSGMLCatalog:
791 * @catal: the catalog
792 *
793 * Convert all the SGML catalog entries as XML ones
794 *
795 * Returns the number of entries converted if successful, -1 otherwise
796 */
797int
798xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
799
800 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
801 return(-1);
802
803 if (xmlDebugCatalogs) {
804 xmlGenericError(xmlGenericErrorContext,
805 "Converting SGML catalog to XML\n");
806 }
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100807 xmlHashScan(catal->sgml, xmlCatalogConvertEntry, &catal);
Daniel Veillard75b96822001-10-11 18:59:45 +0000808 return(0);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000809}
810
Daniel Veillarda7374592001-05-10 14:17:55 +0000811/************************************************************************
812 * *
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000813 * Helper function *
814 * *
815 ************************************************************************/
816
817/**
818 * xmlCatalogUnWrapURN:
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000819 * @urn: an "urn:publicid:" to unwrap
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000820 *
821 * Expand the URN into the equivalent Public Identifier
822 *
823 * Returns the new identifier or NULL, the string must be deallocated
824 * by the caller.
825 */
826static xmlChar *
827xmlCatalogUnWrapURN(const xmlChar *urn) {
828 xmlChar result[2000];
829 unsigned int i = 0;
830
831 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
832 return(NULL);
833 urn += sizeof(XML_URN_PUBID) - 1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800834
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000835 while (*urn != 0) {
Daniel Veillard770075b2004-02-25 10:44:30 +0000836 if (i > sizeof(result) - 4)
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000837 break;
838 if (*urn == '+') {
839 result[i++] = ' ';
840 urn++;
841 } else if (*urn == ':') {
842 result[i++] = '/';
843 result[i++] = '/';
844 urn++;
845 } else if (*urn == ';') {
846 result[i++] = ':';
847 result[i++] = ':';
848 urn++;
849 } else if (*urn == '%') {
Daniel Veillard770075b2004-02-25 10:44:30 +0000850 if ((urn[1] == '2') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000851 result[i++] = '+';
Daniel Veillard770075b2004-02-25 10:44:30 +0000852 else if ((urn[1] == '3') && (urn[2] == 'A'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000853 result[i++] = ':';
Daniel Veillard770075b2004-02-25 10:44:30 +0000854 else if ((urn[1] == '2') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000855 result[i++] = '/';
Daniel Veillard770075b2004-02-25 10:44:30 +0000856 else if ((urn[1] == '3') && (urn[2] == 'B'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000857 result[i++] = ';';
Daniel Veillard770075b2004-02-25 10:44:30 +0000858 else if ((urn[1] == '2') && (urn[2] == '7'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000859 result[i++] = '\'';
Daniel Veillard770075b2004-02-25 10:44:30 +0000860 else if ((urn[1] == '3') && (urn[2] == 'F'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000861 result[i++] = '?';
Daniel Veillard770075b2004-02-25 10:44:30 +0000862 else if ((urn[1] == '2') && (urn[2] == '3'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000863 result[i++] = '#';
Daniel Veillard770075b2004-02-25 10:44:30 +0000864 else if ((urn[1] == '2') && (urn[2] == '5'))
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000865 result[i++] = '%';
866 else {
867 result[i++] = *urn;
868 urn++;
869 continue;
870 }
871 urn += 3;
872 } else {
873 result[i++] = *urn;
874 urn++;
875 }
876 }
877 result[i] = 0;
878
879 return(xmlStrdup(result));
880}
881
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000882/**
883 * xmlParseCatalogFile:
884 * @filename: the filename
885 *
886 * parse an XML file and build a tree. It's like xmlParseFile()
887 * except it bypass all catalog lookups.
888 *
889 * Returns the resulting document tree or NULL in case of error
890 */
891
892xmlDocPtr
893xmlParseCatalogFile(const char *filename) {
894 xmlDocPtr ret;
895 xmlParserCtxtPtr ctxt;
896 char *directory = NULL;
897 xmlParserInputPtr inputStream;
898 xmlParserInputBufferPtr buf;
899
900 ctxt = xmlNewParserCtxt();
901 if (ctxt == NULL) {
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000902#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000903 if (xmlDefaultSAXHandler.error != NULL) {
904 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
905 }
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000906#endif
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000907 return(NULL);
908 }
909
910 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
911 if (buf == NULL) {
912 xmlFreeParserCtxt(ctxt);
913 return(NULL);
914 }
915
916 inputStream = xmlNewInputStream(ctxt);
917 if (inputStream == NULL) {
918 xmlFreeParserCtxt(ctxt);
919 return(NULL);
920 }
921
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +0000922 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000923 inputStream->buf = buf;
Daniel Veillard61551a12012-07-16 16:28:47 +0800924 xmlBufResetInput(buf->buffer, inputStream);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000925
926 inputPush(ctxt, inputStream);
927 if ((ctxt->directory == NULL) && (directory == NULL))
928 directory = xmlParserGetDirectory(filename);
929 if ((ctxt->directory == NULL) && (directory != NULL))
930 ctxt->directory = directory;
Daniel Veillard6990bf32001-08-23 21:17:48 +0000931 ctxt->valid = 0;
932 ctxt->validate = 0;
933 ctxt->loadsubset = 0;
934 ctxt->pedantic = 0;
Daniel Veillard03a53c32004-10-26 16:06:51 +0000935 ctxt->dictNames = 1;
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000936
937 xmlParseDocument(ctxt);
938
939 if (ctxt->wellFormed)
940 ret = ctxt->myDoc;
941 else {
942 ret = NULL;
943 xmlFreeDoc(ctxt->myDoc);
944 ctxt->myDoc = NULL;
945 }
946 xmlFreeParserCtxt(ctxt);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800947
Daniel Veillard9f7b84b2001-08-23 15:31:19 +0000948 return(ret);
949}
950
Daniel Veillard75b96822001-10-11 18:59:45 +0000951/**
952 * xmlLoadFileContent:
953 * @filename: a file path
954 *
955 * Load a file content into memory.
956 *
957 * Returns a pointer to the 0 terminated string or NULL in case of error
958 */
959static xmlChar *
960xmlLoadFileContent(const char *filename)
961{
962#ifdef HAVE_STAT
963 int fd;
964#else
965 FILE *fd;
966#endif
967 int len;
968 long size;
969
970#ifdef HAVE_STAT
971 struct stat info;
972#endif
973 xmlChar *content;
974
975 if (filename == NULL)
976 return (NULL);
977
978#ifdef HAVE_STAT
979 if (stat(filename, &info) < 0)
980 return (NULL);
981#endif
982
983#ifdef HAVE_STAT
Daniel Veillard5aad8322002-12-11 15:59:44 +0000984 if ((fd = open(filename, O_RDONLY)) < 0)
Daniel Veillard75b96822001-10-11 18:59:45 +0000985#else
Daniel Veillard5aad8322002-12-11 15:59:44 +0000986 if ((fd = fopen(filename, "rb")) == NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +0000987#endif
Daniel Veillard5aad8322002-12-11 15:59:44 +0000988 {
Daniel Veillard75b96822001-10-11 18:59:45 +0000989 return (NULL);
990 }
991#ifdef HAVE_STAT
992 size = info.st_size;
993#else
994 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
995 fclose(fd);
996 return (NULL);
997 }
998#endif
Denis Pauke1631e12013-03-10 12:47:37 +0200999 content = (xmlChar*)xmlMallocAtomic(size + 10);
Daniel Veillard75b96822001-10-11 18:59:45 +00001000 if (content == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001001 xmlCatalogErrMemory("allocating catalog data");
Daniel Veillard15d12042014-02-06 10:38:00 +01001002#ifdef HAVE_STAT
1003 close(fd);
1004#else
1005 fclose(fd);
1006#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00001007 return (NULL);
1008 }
1009#ifdef HAVE_STAT
1010 len = read(fd, content, size);
Carlo Braminic43ac662010-10-14 14:27:54 +02001011 close(fd);
Daniel Veillard75b96822001-10-11 18:59:45 +00001012#else
1013 len = fread(content, 1, size, fd);
Carlo Braminic43ac662010-10-14 14:27:54 +02001014 fclose(fd);
Daniel Veillard75b96822001-10-11 18:59:45 +00001015#endif
1016 if (len < 0) {
1017 xmlFree(content);
1018 return (NULL);
1019 }
Daniel Veillard75b96822001-10-11 18:59:45 +00001020 content[len] = 0;
1021
1022 return(content);
1023}
1024
Daniel Veillardc8155052004-07-16 09:03:08 +00001025/**
1026 * xmlCatalogNormalizePublic:
1027 * @pubID: the public ID string
1028 *
1029 * Normalizes the Public Identifier
1030 *
1031 * Implements 6.2. Public Identifier Normalization
1032 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1033 *
1034 * Returns the new string or NULL, the string must be deallocated
1035 * by the caller.
1036 */
1037static xmlChar *
1038xmlCatalogNormalizePublic(const xmlChar *pubID)
1039{
1040 int ok = 1;
1041 int white;
1042 const xmlChar *p;
1043 xmlChar *ret;
1044 xmlChar *q;
1045
1046 if (pubID == NULL)
1047 return(NULL);
1048
1049 white = 1;
1050 for (p = pubID;*p != 0 && ok;p++) {
1051 if (!xmlIsBlank_ch(*p))
1052 white = 0;
1053 else if (*p == 0x20 && !white)
1054 white = 1;
1055 else
1056 ok = 0;
1057 }
1058 if (ok && !white) /* is normalized */
1059 return(NULL);
1060
1061 ret = xmlStrdup(pubID);
1062 q = ret;
1063 white = 0;
1064 for (p = pubID;*p != 0;p++) {
1065 if (xmlIsBlank_ch(*p)) {
1066 if (q != ret)
1067 white = 1;
1068 } else {
1069 if (white) {
1070 *(q++) = 0x20;
1071 white = 0;
1072 }
1073 *(q++) = *p;
1074 }
1075 }
1076 *q = 0;
1077 return(ret);
1078}
1079
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001080/************************************************************************
1081 * *
Daniel Veillard344cee72001-08-20 00:08:40 +00001082 * The XML Catalog parser *
1083 * *
1084 ************************************************************************/
1085
1086static xmlCatalogEntryPtr
1087xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001088static void
1089xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001090 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
Daniel Veillardcda96922001-08-21 10:56:31 +00001091static xmlChar *
1092xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1093 const xmlChar *sysID);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001094static xmlChar *
1095xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1096
Daniel Veillard344cee72001-08-20 00:08:40 +00001097
Daniel Veillard75b96822001-10-11 18:59:45 +00001098/**
1099 * xmlGetXMLCatalogEntryType:
1100 * @name: the name
1101 *
1102 * lookup the internal type associated to an XML catalog entry name
1103 *
Daniel Veillard06d25242004-02-25 13:01:42 +00001104 * Returns the type associated with that name
Daniel Veillard75b96822001-10-11 18:59:45 +00001105 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001106static xmlCatalogEntryType
1107xmlGetXMLCatalogEntryType(const xmlChar *name) {
1108 xmlCatalogEntryType type = XML_CATA_NONE;
1109 if (xmlStrEqual(name, (const xmlChar *) "system"))
1110 type = XML_CATA_SYSTEM;
1111 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1112 type = XML_CATA_PUBLIC;
1113 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1114 type = XML_CATA_REWRITE_SYSTEM;
1115 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1116 type = XML_CATA_DELEGATE_PUBLIC;
1117 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1118 type = XML_CATA_DELEGATE_SYSTEM;
1119 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1120 type = XML_CATA_URI;
1121 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1122 type = XML_CATA_REWRITE_URI;
1123 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1124 type = XML_CATA_DELEGATE_URI;
1125 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1126 type = XML_CATA_NEXT_CATALOG;
1127 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1128 type = XML_CATA_CATALOG;
1129 return(type);
1130}
1131
Daniel Veillard75b96822001-10-11 18:59:45 +00001132/**
1133 * xmlParseXMLCatalogOneNode:
1134 * @cur: the XML node
1135 * @type: the type of Catalog entry
1136 * @name: the name of the node
1137 * @attrName: the attribute holding the value
1138 * @uriAttrName: the attribute holding the URI-Reference
1139 * @prefer: the PUBLIC vs. SYSTEM current preference value
William M. Brackb7b54de2004-10-06 16:38:01 +00001140 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001141 *
1142 * Finishes the examination of an XML tree node of a catalog and build
1143 * a Catalog entry from it.
1144 *
1145 * Returns the new Catalog entry node or NULL in case of error.
1146 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001147static xmlCatalogEntryPtr
1148xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1149 const xmlChar *name, const xmlChar *attrName,
William M. Brackb7b54de2004-10-06 16:38:01 +00001150 const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1151 xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001152 int ok = 1;
1153 xmlChar *uriValue;
1154 xmlChar *nameValue = NULL;
1155 xmlChar *base = NULL;
1156 xmlChar *URL = NULL;
1157 xmlCatalogEntryPtr ret = NULL;
1158
1159 if (attrName != NULL) {
1160 nameValue = xmlGetProp(cur, attrName);
1161 if (nameValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001162 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1163 "%s entry lacks '%s'\n", name, attrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001164 ok = 0;
1165 }
1166 }
1167 uriValue = xmlGetProp(cur, uriAttrName);
1168 if (uriValue == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001169 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1170 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001171 ok = 0;
1172 }
1173 if (!ok) {
1174 if (nameValue != NULL)
1175 xmlFree(nameValue);
1176 if (uriValue != NULL)
1177 xmlFree(uriValue);
1178 return(NULL);
1179 }
1180
1181 base = xmlNodeGetBase(cur->doc, cur);
1182 URL = xmlBuildURI(uriValue, base);
1183 if (URL != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001184 if (xmlDebugCatalogs > 1) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001185 if (nameValue != NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001186 xmlGenericError(xmlGenericErrorContext,
1187 "Found %s: '%s' '%s'\n", name, nameValue, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001188 else
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001189 xmlGenericError(xmlGenericErrorContext,
1190 "Found %s: '%s'\n", name, URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001191 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001192 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001193 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001194 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
Daniel Veillard344cee72001-08-20 00:08:40 +00001195 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1196 }
1197 if (nameValue != NULL)
1198 xmlFree(nameValue);
1199 if (uriValue != NULL)
1200 xmlFree(uriValue);
1201 if (base != NULL)
1202 xmlFree(base);
1203 if (URL != NULL)
1204 xmlFree(URL);
1205 return(ret);
1206}
1207
Daniel Veillard75b96822001-10-11 18:59:45 +00001208/**
1209 * xmlParseXMLCatalogNode:
1210 * @cur: the XML node
1211 * @prefer: the PUBLIC vs. SYSTEM current preference value
1212 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001213 * @cgroup: the group which includes this node
Daniel Veillard75b96822001-10-11 18:59:45 +00001214 *
1215 * Examines an XML tree node of a catalog and build
1216 * a Catalog entry from it adding it to its parent. The examination can
1217 * be recursive.
1218 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001219static void
1220xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001221 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
Daniel Veillard344cee72001-08-20 00:08:40 +00001222{
Daniel Veillard344cee72001-08-20 00:08:40 +00001223 xmlChar *base = NULL;
1224 xmlCatalogEntryPtr entry = NULL;
1225
1226 if (cur == NULL)
1227 return;
1228 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1229 xmlChar *prop;
William M. Brackb7b54de2004-10-06 16:38:01 +00001230 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
Daniel Veillard344cee72001-08-20 00:08:40 +00001231
1232 prop = xmlGetProp(cur, BAD_CAST "prefer");
1233 if (prop != NULL) {
1234 if (xmlStrEqual(prop, BAD_CAST "system")) {
1235 prefer = XML_CATA_PREFER_SYSTEM;
1236 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1237 prefer = XML_CATA_PREFER_PUBLIC;
1238 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001239 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1240 "Invalid value for prefer: '%s'\n",
1241 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001242 }
1243 xmlFree(prop);
William M. Brackb7b54de2004-10-06 16:38:01 +00001244 pref = prefer;
Daniel Veillard344cee72001-08-20 00:08:40 +00001245 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001246 prop = xmlGetProp(cur, BAD_CAST "id");
1247 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1248 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
William M. Brack181a1ca2004-10-06 18:00:29 +00001249 xmlFree(prop);
Daniel Veillard344cee72001-08-20 00:08:40 +00001250 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1251 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
William M. Brackb7b54de2004-10-06 16:38:01 +00001252 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001253 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1254 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
William M. Brackb7b54de2004-10-06 16:38:01 +00001255 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001256 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1257 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1258 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001259 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001260 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1261 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1262 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001263 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001264 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1265 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1266 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001267 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001268 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1269 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1270 BAD_CAST "uri", BAD_CAST "name",
William M. Brackb7b54de2004-10-06 16:38:01 +00001271 BAD_CAST "uri", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001272 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1273 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1274 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001275 BAD_CAST "rewritePrefix", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001276 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1277 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1278 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
William M. Brackb7b54de2004-10-06 16:38:01 +00001279 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001280 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1281 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1282 BAD_CAST "nextCatalog", NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001283 BAD_CAST "catalog", prefer, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001284 }
William M. Brackb031cef2004-11-05 16:34:22 +00001285 if (entry != NULL) {
1286 if (parent != NULL) {
1287 entry->parent = parent;
1288 if (parent->children == NULL)
1289 parent->children = entry;
1290 else {
1291 xmlCatalogEntryPtr prev;
Daniel Veillard344cee72001-08-20 00:08:40 +00001292
William M. Brackb031cef2004-11-05 16:34:22 +00001293 prev = parent->children;
1294 while (prev->next != NULL)
1295 prev = prev->next;
1296 prev->next = entry;
1297 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001298 }
William M. Brackb031cef2004-11-05 16:34:22 +00001299 if (entry->type == XML_CATA_GROUP) {
1300 /*
1301 * Recurse to propagate prefer to the subtree
1302 * (xml:base handling is automated)
1303 */
1304 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1305 }
William M. Brackb7b54de2004-10-06 16:38:01 +00001306 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001307 if (base != NULL)
1308 xmlFree(base);
Daniel Veillard344cee72001-08-20 00:08:40 +00001309}
1310
Daniel Veillard75b96822001-10-11 18:59:45 +00001311/**
1312 * xmlParseXMLCatalogNodeList:
1313 * @cur: the XML node list of siblings
1314 * @prefer: the PUBLIC vs. SYSTEM current preference value
1315 * @parent: the parent Catalog entry
William M. Brackb7b54de2004-10-06 16:38:01 +00001316 * @cgroup: the group which includes this list
Daniel Veillard75b96822001-10-11 18:59:45 +00001317 *
1318 * Examines a list of XML sibling nodes of a catalog and build
1319 * a list of Catalog entry from it adding it to the parent.
1320 * The examination will recurse to examine node subtrees.
1321 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001322static void
1323xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
William M. Brackb7b54de2004-10-06 16:38:01 +00001324 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
Daniel Veillard344cee72001-08-20 00:08:40 +00001325 while (cur != NULL) {
1326 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1327 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
William M. Brackb7b54de2004-10-06 16:38:01 +00001328 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
Daniel Veillard344cee72001-08-20 00:08:40 +00001329 }
1330 cur = cur->next;
1331 }
1332 /* TODO: sort the list according to REWRITE lengths and prefer value */
1333}
1334
Daniel Veillard75b96822001-10-11 18:59:45 +00001335/**
Daniel Veillard75b96822001-10-11 18:59:45 +00001336 * xmlParseXMLCatalogFile:
1337 * @prefer: the PUBLIC vs. SYSTEM current preference value
1338 * @filename: the filename for the catalog
1339 *
1340 * Parses the catalog file to extract the XML tree and then analyze the
1341 * tree to build a list of Catalog entries corresponding to this catalog
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001342 *
Daniel Veillard75b96822001-10-11 18:59:45 +00001343 * Returns the resulting Catalog entries list
1344 */
Daniel Veillard344cee72001-08-20 00:08:40 +00001345static xmlCatalogEntryPtr
1346xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1347 xmlDocPtr doc;
1348 xmlNodePtr cur;
1349 xmlChar *prop;
1350 xmlCatalogEntryPtr parent = NULL;
1351
1352 if (filename == NULL)
1353 return(NULL);
1354
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001355 doc = xmlParseCatalogFile((const char *) filename);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001356 if (doc == NULL) {
1357 if (xmlDebugCatalogs)
1358 xmlGenericError(xmlGenericErrorContext,
1359 "Failed to parse catalog %s\n", filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001360 return(NULL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001361 }
1362
1363 if (xmlDebugCatalogs)
1364 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard3c01b1d2001-10-17 15:58:35 +00001365 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
Daniel Veillard344cee72001-08-20 00:08:40 +00001366
1367 cur = xmlDocGetRootElement(doc);
1368 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1369 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1370 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1371
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001372 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00001373 (const xmlChar *)filename, NULL, prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001374 if (parent == NULL) {
1375 xmlFreeDoc(doc);
1376 return(NULL);
1377 }
1378
1379 prop = xmlGetProp(cur, BAD_CAST "prefer");
1380 if (prop != NULL) {
1381 if (xmlStrEqual(prop, BAD_CAST "system")) {
1382 prefer = XML_CATA_PREFER_SYSTEM;
1383 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1384 prefer = XML_CATA_PREFER_PUBLIC;
1385 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001386 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1387 "Invalid value for prefer: '%s'\n",
1388 prop, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001389 }
1390 xmlFree(prop);
1391 }
1392 cur = cur->children;
William M. Brackb7b54de2004-10-06 16:38:01 +00001393 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001394 } else {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001395 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1396 "File %s is not an XML Catalog\n",
1397 filename, NULL, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001398 xmlFreeDoc(doc);
1399 return(NULL);
1400 }
1401 xmlFreeDoc(doc);
1402 return(parent);
1403}
1404
Daniel Veillardcda96922001-08-21 10:56:31 +00001405/**
1406 * xmlFetchXMLCatalogFile:
1407 * @catal: an existing but incomplete catalog entry
1408 *
1409 * Fetch and parse the subcatalog referenced by an entry
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001410 *
Daniel Veillardcda96922001-08-21 10:56:31 +00001411 * Returns 0 in case of success, -1 otherwise
1412 */
1413static int
1414xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001415 xmlCatalogEntryPtr doc;
Daniel Veillardcda96922001-08-21 10:56:31 +00001416
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001417 if (catal == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001418 return(-1);
Daniel Veillardc853b322001-11-06 15:24:37 +00001419 if (catal->URL == NULL)
Daniel Veillardcda96922001-08-21 10:56:31 +00001420 return(-1);
Daniel Veillardcda96922001-08-21 10:56:31 +00001421
Daniel Veillard81463942001-10-16 12:34:39 +00001422 /*
1423 * lock the whole catalog for modification
1424 */
1425 xmlRMutexLock(xmlCatalogMutex);
1426 if (catal->children != NULL) {
1427 /* Okay someone else did it in the meantime */
1428 xmlRMutexUnlock(xmlCatalogMutex);
1429 return(0);
Daniel Veillard81463942001-10-16 12:34:39 +00001430 }
1431
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001432 if (xmlCatalogXMLFiles != NULL) {
1433 doc = (xmlCatalogEntryPtr)
Daniel Veillardc853b322001-11-06 15:24:37 +00001434 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001435 if (doc != NULL) {
1436 if (xmlDebugCatalogs)
1437 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001438 "Found %s in file hash\n", catal->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001439
1440 if (catal->type == XML_CATA_CATALOG)
1441 catal->children = doc->children;
1442 else
1443 catal->children = doc;
1444 catal->dealloc = 0;
1445 xmlRMutexUnlock(xmlCatalogMutex);
1446 return(0);
1447 }
1448 if (xmlDebugCatalogs)
1449 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001450 "%s not found in file hash\n", catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001451 }
1452
Daniel Veillardcda96922001-08-21 10:56:31 +00001453 /*
Daniel Veillard75b96822001-10-11 18:59:45 +00001454 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001455 * use the existing catalog, there is no recursion allowed at
Daniel Veillard75b96822001-10-11 18:59:45 +00001456 * that level.
Daniel Veillardcda96922001-08-21 10:56:31 +00001457 */
Daniel Veillardc853b322001-11-06 15:24:37 +00001458 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00001459 if (doc == NULL) {
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001460 catal->type = XML_CATA_BROKEN_CATALOG;
Daniel Veillard81463942001-10-16 12:34:39 +00001461 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001462 return(-1);
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001463 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001464
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001465 if (catal->type == XML_CATA_CATALOG)
1466 catal->children = doc->children;
1467 else
1468 catal->children = doc;
1469
1470 doc->dealloc = 1;
1471
Daniel Veillard81463942001-10-16 12:34:39 +00001472 if (xmlCatalogXMLFiles == NULL)
1473 xmlCatalogXMLFiles = xmlHashCreate(10);
1474 if (xmlCatalogXMLFiles != NULL) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001475 if (xmlDebugCatalogs)
1476 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001477 "%s added to file hash\n", catal->URL);
1478 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
Daniel Veillardcda96922001-08-21 10:56:31 +00001479 }
Daniel Veillard81463942001-10-16 12:34:39 +00001480 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00001481 return(0);
1482}
1483
Daniel Veillard75b96822001-10-11 18:59:45 +00001484/************************************************************************
1485 * *
1486 * XML Catalog handling *
1487 * *
1488 ************************************************************************/
Daniel Veillard344cee72001-08-20 00:08:40 +00001489
1490/**
1491 * xmlAddXMLCatalog:
1492 * @catal: top of an XML catalog
1493 * @type: the type of record to add to the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001494 * @orig: the system, public or prefix to match (or NULL)
Daniel Veillard344cee72001-08-20 00:08:40 +00001495 * @replace: the replacement value for the match
1496 *
1497 * Add an entry in the XML catalog, it may overwrite existing but
1498 * different entries.
1499 *
1500 * Returns 0 if successful, -1 otherwise
1501 */
1502static int
1503xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1504 const xmlChar *orig, const xmlChar *replace) {
1505 xmlCatalogEntryPtr cur;
1506 xmlCatalogEntryType typ;
Daniel Veillardc853b322001-11-06 15:24:37 +00001507 int doregister = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +00001508
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001509 if ((catal == NULL) ||
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001510 ((catal->type != XML_CATA_CATALOG) &&
1511 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillard344cee72001-08-20 00:08:40 +00001512 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001513 if (catal->children == NULL) {
1514 xmlFetchXMLCatalogFile(catal);
1515 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001516 if (catal->children == NULL)
1517 doregister = 1;
1518
Daniel Veillard344cee72001-08-20 00:08:40 +00001519 typ = xmlGetXMLCatalogEntryType(type);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001520 if (typ == XML_CATA_NONE) {
1521 if (xmlDebugCatalogs)
1522 xmlGenericError(xmlGenericErrorContext,
1523 "Failed to add unknown element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001524 return(-1);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001525 }
Daniel Veillard344cee72001-08-20 00:08:40 +00001526
1527 cur = catal->children;
1528 /*
1529 * Might be a simple "update in place"
1530 */
1531 if (cur != NULL) {
1532 while (cur != NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +00001533 if ((orig != NULL) && (cur->type == typ) &&
1534 (xmlStrEqual(orig, cur->name))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001535 if (xmlDebugCatalogs)
1536 xmlGenericError(xmlGenericErrorContext,
1537 "Updating element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001538 if (cur->value != NULL)
1539 xmlFree(cur->value);
Daniel Veillardc853b322001-11-06 15:24:37 +00001540 if (cur->URL != NULL)
1541 xmlFree(cur->URL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001542 cur->value = xmlStrdup(replace);
Daniel Veillardc853b322001-11-06 15:24:37 +00001543 cur->URL = xmlStrdup(replace);
Daniel Veillardcda96922001-08-21 10:56:31 +00001544 return(0);
Daniel Veillard344cee72001-08-20 00:08:40 +00001545 }
1546 if (cur->next == NULL)
1547 break;
1548 cur = cur->next;
1549 }
1550 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001551 if (xmlDebugCatalogs)
1552 xmlGenericError(xmlGenericErrorContext,
1553 "Adding element %s to catalog\n", type);
Daniel Veillard344cee72001-08-20 00:08:40 +00001554 if (cur == NULL)
Daniel Veillardc853b322001-11-06 15:24:37 +00001555 catal->children = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001556 NULL, catal->prefer, NULL);
Daniel Veillard344cee72001-08-20 00:08:40 +00001557 else
Daniel Veillardc853b322001-11-06 15:24:37 +00001558 cur->next = xmlNewCatalogEntry(typ, orig, replace,
William M. Brackb7b54de2004-10-06 16:38:01 +00001559 NULL, catal->prefer, NULL);
Daniel Veillardc853b322001-11-06 15:24:37 +00001560 if (doregister) {
Daniel Veillard27bec142006-02-24 20:22:27 +00001561 catal->type = XML_CATA_CATALOG;
Denis Pauke1631e12013-03-10 12:47:37 +02001562 cur = (xmlCatalogEntryPtr)xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
Daniel Veillardc853b322001-11-06 15:24:37 +00001563 if (cur != NULL)
1564 cur->children = catal->children;
1565 }
1566
Daniel Veillardcda96922001-08-21 10:56:31 +00001567 return(0);
1568}
1569
1570/**
1571 * xmlDelXMLCatalog:
1572 * @catal: top of an XML catalog
Daniel Veillard60087f32001-10-10 09:45:09 +00001573 * @value: the value to remove from the catalog
Daniel Veillardcda96922001-08-21 10:56:31 +00001574 *
1575 * Remove entries in the XML catalog where the value or the URI
1576 * is equal to @value
1577 *
1578 * Returns the number of entries removed if successful, -1 otherwise
1579 */
1580static int
1581xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
Daniel Veillardc853b322001-11-06 15:24:37 +00001582 xmlCatalogEntryPtr cur;
Daniel Veillardcda96922001-08-21 10:56:31 +00001583 int ret = 0;
1584
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001585 if ((catal == NULL) ||
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001586 ((catal->type != XML_CATA_CATALOG) &&
1587 (catal->type != XML_CATA_BROKEN_CATALOG)))
Daniel Veillardcda96922001-08-21 10:56:31 +00001588 return(-1);
1589 if (value == NULL)
1590 return(-1);
Daniel Veillardffe09c92001-11-05 14:21:47 +00001591 if (catal->children == NULL) {
1592 xmlFetchXMLCatalogFile(catal);
1593 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001594
1595 /*
1596 * Scan the children
1597 */
1598 cur = catal->children;
Daniel Veillardcda96922001-08-21 10:56:31 +00001599 while (cur != NULL) {
1600 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1601 (xmlStrEqual(value, cur->value))) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001602 if (xmlDebugCatalogs) {
1603 if (cur->name != NULL)
1604 xmlGenericError(xmlGenericErrorContext,
1605 "Removing element %s from catalog\n", cur->name);
1606 else
1607 xmlGenericError(xmlGenericErrorContext,
1608 "Removing element %s from catalog\n", cur->value);
1609 }
Daniel Veillardc853b322001-11-06 15:24:37 +00001610 cur->type = XML_CATA_REMOVED;
Daniel Veillardcda96922001-08-21 10:56:31 +00001611 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001612 cur = cur->next;
1613 }
1614 return(ret);
1615}
1616
1617/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001618 * xmlCatalogXMLResolve:
1619 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001620 * @pubID: the public ID string
1621 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001622 *
1623 * Do a complete resolution lookup of an External Identifier for a
1624 * list of catalog entries.
1625 *
1626 * Implements (or tries to) 7.1. External Identifier Resolution
1627 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1628 *
1629 * Returns the URI of the resource or NULL if not found
1630 */
1631static xmlChar *
1632xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1633 const xmlChar *sysID) {
1634 xmlChar *ret = NULL;
1635 xmlCatalogEntryPtr cur;
1636 int haveDelegate = 0;
1637 int haveNext = 0;
1638
1639 /*
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001640 * protection against loops
1641 */
1642 if (catal->depth > MAX_CATAL_DEPTH) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00001643 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1644 "Detected recursion in catalog %s\n",
1645 catal->name, NULL, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001646 return(NULL);
1647 }
1648 catal->depth++;
1649
1650 /*
Daniel Veillardcda96922001-08-21 10:56:31 +00001651 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1652 */
1653 if (sysID != NULL) {
1654 xmlCatalogEntryPtr rewrite = NULL;
1655 int lenrewrite = 0, len;
1656 cur = catal;
1657 haveDelegate = 0;
1658 while (cur != NULL) {
1659 switch (cur->type) {
1660 case XML_CATA_SYSTEM:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001661 if (xmlStrEqual(sysID, cur->name)) {
1662 if (xmlDebugCatalogs)
1663 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard890b5492006-02-23 08:14:00 +00001664 "Found system match %s, using %s\n",
1665 cur->name, cur->URL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001666 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001667 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001668 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001669 break;
1670 case XML_CATA_REWRITE_SYSTEM:
1671 len = xmlStrlen(cur->name);
1672 if ((len > lenrewrite) &&
1673 (!xmlStrncmp(sysID, cur->name, len))) {
1674 lenrewrite = len;
1675 rewrite = cur;
1676 }
1677 break;
1678 case XML_CATA_DELEGATE_SYSTEM:
1679 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1680 haveDelegate++;
1681 break;
1682 case XML_CATA_NEXT_CATALOG:
1683 haveNext++;
1684 break;
1685 default:
1686 break;
1687 }
1688 cur = cur->next;
1689 }
1690 if (rewrite != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001691 if (xmlDebugCatalogs)
1692 xmlGenericError(xmlGenericErrorContext,
1693 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001694 ret = xmlStrdup(rewrite->URL);
Daniel Veillardcda96922001-08-21 10:56:31 +00001695 if (ret != NULL)
1696 ret = xmlStrcat(ret, &sysID[lenrewrite]);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001697 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001698 return(ret);
1699 }
1700 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001701 const xmlChar *delegates[MAX_DELEGATE];
1702 int nbList = 0, i;
1703
Daniel Veillardcda96922001-08-21 10:56:31 +00001704 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001705 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001706 * matches when the list was produced.
1707 */
1708 cur = catal;
1709 while (cur != NULL) {
1710 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1711 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001712 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001713 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001714 break;
1715 if (i < nbList) {
1716 cur = cur->next;
1717 continue;
1718 }
1719 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001720 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001721
Daniel Veillardcda96922001-08-21 10:56:31 +00001722 if (cur->children == NULL) {
1723 xmlFetchXMLCatalogFile(cur);
1724 }
1725 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001726 if (xmlDebugCatalogs)
1727 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001728 "Trying system delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001729 ret = xmlCatalogListXMLResolve(
1730 cur->children, NULL, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001731 if (ret != NULL) {
1732 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001733 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001734 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001735 }
1736 }
1737 cur = cur->next;
1738 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001739 /*
1740 * Apply the cut algorithm explained in 4/
1741 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001742 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001743 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001744 }
1745 }
1746 /*
1747 * Then tries 5/ 6/ if a public ID is provided
1748 */
1749 if (pubID != NULL) {
1750 cur = catal;
1751 haveDelegate = 0;
1752 while (cur != NULL) {
1753 switch (cur->type) {
1754 case XML_CATA_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001755 if (xmlStrEqual(pubID, cur->name)) {
1756 if (xmlDebugCatalogs)
1757 xmlGenericError(xmlGenericErrorContext,
1758 "Found public match %s\n", cur->name);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001759 catal->depth--;
Daniel Veillardc853b322001-11-06 15:24:37 +00001760 return(xmlStrdup(cur->URL));
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001761 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001762 break;
1763 case XML_CATA_DELEGATE_PUBLIC:
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001764 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1765 (cur->prefer == XML_CATA_PREFER_PUBLIC))
Daniel Veillardcda96922001-08-21 10:56:31 +00001766 haveDelegate++;
1767 break;
1768 case XML_CATA_NEXT_CATALOG:
1769 if (sysID == NULL)
1770 haveNext++;
1771 break;
1772 default:
1773 break;
1774 }
1775 cur = cur->next;
1776 }
1777 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001778 const xmlChar *delegates[MAX_DELEGATE];
1779 int nbList = 0, i;
1780
Daniel Veillardcda96922001-08-21 10:56:31 +00001781 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001782 * Assume the entries have been sorted by decreasing substring
Daniel Veillardcda96922001-08-21 10:56:31 +00001783 * matches when the list was produced.
1784 */
1785 cur = catal;
1786 while (cur != NULL) {
1787 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001788 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1789 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001790
1791 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001792 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001793 break;
1794 if (i < nbList) {
1795 cur = cur->next;
1796 continue;
1797 }
1798 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001799 delegates[nbList++] = cur->URL;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001800
Daniel Veillardcda96922001-08-21 10:56:31 +00001801 if (cur->children == NULL) {
1802 xmlFetchXMLCatalogFile(cur);
1803 }
1804 if (cur->children != NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001805 if (xmlDebugCatalogs)
1806 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001807 "Trying public delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001808 ret = xmlCatalogListXMLResolve(
1809 cur->children, pubID, NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001810 if (ret != NULL) {
1811 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001812 return(ret);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001813 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001814 }
1815 }
1816 cur = cur->next;
1817 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001818 /*
1819 * Apply the cut algorithm explained in 4/
1820 */
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001821 catal->depth--;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00001822 return(XML_CATAL_BREAK);
Daniel Veillardcda96922001-08-21 10:56:31 +00001823 }
1824 }
1825 if (haveNext) {
1826 cur = catal;
1827 while (cur != NULL) {
1828 if (cur->type == XML_CATA_NEXT_CATALOG) {
1829 if (cur->children == NULL) {
1830 xmlFetchXMLCatalogFile(cur);
1831 }
1832 if (cur->children != NULL) {
Daniel Veillard64339542001-08-21 12:57:59 +00001833 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001834 if (ret != NULL) {
1835 catal->depth--;
Daniel Veillard64339542001-08-21 12:57:59 +00001836 return(ret);
Daniel Veillardbe8d9d32007-06-12 09:14:11 +00001837 } else if (catal->depth > MAX_CATAL_DEPTH) {
1838 return(NULL);
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001839 }
Daniel Veillardcda96922001-08-21 10:56:31 +00001840 }
1841 }
1842 cur = cur->next;
1843 }
1844 }
1845
Daniel Veillard5ee43b02003-08-04 00:58:46 +00001846 catal->depth--;
Daniel Veillardcda96922001-08-21 10:56:31 +00001847 return(NULL);
1848}
1849
1850/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001851 * xmlCatalogXMLResolveURI:
1852 * @catal: a catalog list
1853 * @URI: the URI
Daniel Veillard06d25242004-02-25 13:01:42 +00001854 * @sysID: the system ID string
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001855 *
1856 * Do a complete resolution lookup of an External Identifier for a
1857 * list of catalog entries.
1858 *
1859 * Implements (or tries to) 7.2.2. URI Resolution
1860 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1861 *
1862 * Returns the URI of the resource or NULL if not found
1863 */
1864static xmlChar *
1865xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1866 xmlChar *ret = NULL;
1867 xmlCatalogEntryPtr cur;
1868 int haveDelegate = 0;
1869 int haveNext = 0;
1870 xmlCatalogEntryPtr rewrite = NULL;
1871 int lenrewrite = 0, len;
1872
1873 if (catal == NULL)
1874 return(NULL);
1875
1876 if (URI == NULL)
1877 return(NULL);
1878
Daniel Veillardbe8d9d32007-06-12 09:14:11 +00001879 if (catal->depth > MAX_CATAL_DEPTH) {
1880 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1881 "Detected recursion in catalog %s\n",
1882 catal->name, NULL, NULL);
1883 return(NULL);
1884 }
1885
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001886 /*
1887 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1888 */
1889 cur = catal;
1890 haveDelegate = 0;
1891 while (cur != NULL) {
1892 switch (cur->type) {
1893 case XML_CATA_URI:
1894 if (xmlStrEqual(URI, cur->name)) {
1895 if (xmlDebugCatalogs)
1896 xmlGenericError(xmlGenericErrorContext,
1897 "Found URI match %s\n", cur->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001898 return(xmlStrdup(cur->URL));
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001899 }
1900 break;
1901 case XML_CATA_REWRITE_URI:
1902 len = xmlStrlen(cur->name);
1903 if ((len > lenrewrite) &&
1904 (!xmlStrncmp(URI, cur->name, len))) {
1905 lenrewrite = len;
1906 rewrite = cur;
1907 }
1908 break;
1909 case XML_CATA_DELEGATE_URI:
1910 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1911 haveDelegate++;
1912 break;
1913 case XML_CATA_NEXT_CATALOG:
1914 haveNext++;
1915 break;
1916 default:
1917 break;
1918 }
1919 cur = cur->next;
1920 }
1921 if (rewrite != NULL) {
1922 if (xmlDebugCatalogs)
1923 xmlGenericError(xmlGenericErrorContext,
1924 "Using rewriting rule %s\n", rewrite->name);
Daniel Veillardc853b322001-11-06 15:24:37 +00001925 ret = xmlStrdup(rewrite->URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001926 if (ret != NULL)
1927 ret = xmlStrcat(ret, &URI[lenrewrite]);
1928 return(ret);
1929 }
1930 if (haveDelegate) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001931 const xmlChar *delegates[MAX_DELEGATE];
1932 int nbList = 0, i;
1933
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001934 /*
1935 * Assume the entries have been sorted by decreasing substring
1936 * matches when the list was produced.
1937 */
1938 cur = catal;
1939 while (cur != NULL) {
Daniel Veillard652d8a92003-02-04 19:28:49 +00001940 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1941 (cur->type == XML_CATA_DELEGATE_URI)) &&
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001942 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00001943 for (i = 0;i < nbList;i++)
Daniel Veillardc853b322001-11-06 15:24:37 +00001944 if (xmlStrEqual(cur->URL, delegates[i]))
Daniel Veillard6990bf32001-08-23 21:17:48 +00001945 break;
1946 if (i < nbList) {
1947 cur = cur->next;
1948 continue;
1949 }
1950 if (nbList < MAX_DELEGATE)
Daniel Veillardc853b322001-11-06 15:24:37 +00001951 delegates[nbList++] = cur->URL;
Daniel Veillard6990bf32001-08-23 21:17:48 +00001952
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001953 if (cur->children == NULL) {
1954 xmlFetchXMLCatalogFile(cur);
1955 }
1956 if (cur->children != NULL) {
1957 if (xmlDebugCatalogs)
1958 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc853b322001-11-06 15:24:37 +00001959 "Trying URI delegate %s\n", cur->URL);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00001960 ret = xmlCatalogListXMLResolveURI(
1961 cur->children, URI);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00001962 if (ret != NULL)
1963 return(ret);
1964 }
1965 }
1966 cur = cur->next;
1967 }
1968 /*
1969 * Apply the cut algorithm explained in 4/
1970 */
1971 return(XML_CATAL_BREAK);
1972 }
1973 if (haveNext) {
1974 cur = catal;
1975 while (cur != NULL) {
1976 if (cur->type == XML_CATA_NEXT_CATALOG) {
1977 if (cur->children == NULL) {
1978 xmlFetchXMLCatalogFile(cur);
1979 }
1980 if (cur->children != NULL) {
1981 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1982 if (ret != NULL)
1983 return(ret);
1984 }
1985 }
1986 cur = cur->next;
1987 }
1988 }
1989
1990 return(NULL);
1991}
1992
1993/**
Daniel Veillardcda96922001-08-21 10:56:31 +00001994 * xmlCatalogListXMLResolve:
1995 * @catal: a catalog list
Daniel Veillard06d25242004-02-25 13:01:42 +00001996 * @pubID: the public ID string
1997 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00001998 *
1999 * Do a complete resolution lookup of an External Identifier for a
2000 * list of catalogs
2001 *
2002 * Implements (or tries to) 7.1. External Identifier Resolution
2003 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2004 *
2005 * Returns the URI of the resource or NULL if not found
2006 */
2007static xmlChar *
2008xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
2009 const xmlChar *sysID) {
2010 xmlChar *ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002011 xmlChar *urnID = NULL;
Daniel Veillardc8155052004-07-16 09:03:08 +00002012 xmlChar *normid;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002013
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002014 if (catal == NULL)
2015 return(NULL);
2016 if ((pubID == NULL) && (sysID == NULL))
2017 return(NULL);
2018
Daniel Veillardc8155052004-07-16 09:03:08 +00002019 normid = xmlCatalogNormalizePublic(pubID);
2020 if (normid != NULL)
2021 pubID = (*normid != 0 ? normid : NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002022
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002023 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2024 urnID = xmlCatalogUnWrapURN(pubID);
2025 if (xmlDebugCatalogs) {
2026 if (urnID == NULL)
2027 xmlGenericError(xmlGenericErrorContext,
2028 "Public URN ID %s expanded to NULL\n", pubID);
2029 else
2030 xmlGenericError(xmlGenericErrorContext,
2031 "Public URN ID expanded to %s\n", urnID);
2032 }
2033 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2034 if (urnID != NULL)
2035 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002036 if (normid != NULL)
2037 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002038 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002039 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002040 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2041 urnID = xmlCatalogUnWrapURN(sysID);
2042 if (xmlDebugCatalogs) {
2043 if (urnID == NULL)
2044 xmlGenericError(xmlGenericErrorContext,
2045 "System URN ID %s expanded to NULL\n", sysID);
2046 else
2047 xmlGenericError(xmlGenericErrorContext,
2048 "System URN ID expanded to %s\n", urnID);
2049 }
2050 if (pubID == NULL)
2051 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2052 else if (xmlStrEqual(pubID, urnID))
2053 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2054 else {
Daniel Veillard770075b2004-02-25 10:44:30 +00002055 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002056 }
2057 if (urnID != NULL)
2058 xmlFree(urnID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002059 if (normid != NULL)
2060 xmlFree(normid);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002061 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002062 }
2063 while (catal != NULL) {
2064 if (catal->type == XML_CATA_CATALOG) {
2065 if (catal->children == NULL) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002066 xmlFetchXMLCatalogFile(catal);
Daniel Veillardcda96922001-08-21 10:56:31 +00002067 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002068 if (catal->children != NULL) {
2069 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002070 if (ret != NULL) {
Daniel Veillardbe8d9d32007-06-12 09:14:11 +00002071 break;
2072 } else if ((catal->children != NULL) &&
2073 (catal->children->depth > MAX_CATAL_DEPTH)) {
2074 ret = NULL;
2075 break;
2076 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002077 }
Daniel Veillardcda96922001-08-21 10:56:31 +00002078 }
2079 catal = catal->next;
2080 }
Daniel Veillardbe8d9d32007-06-12 09:14:11 +00002081 if (normid != NULL)
2082 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002083 return(ret);
Daniel Veillard344cee72001-08-20 00:08:40 +00002084}
2085
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002086/**
2087 * xmlCatalogListXMLResolveURI:
2088 * @catal: a catalog list
2089 * @URI: the URI
2090 *
2091 * Do a complete resolution lookup of an URI for a list of catalogs
2092 *
2093 * Implements (or tries to) 7.2. URI Resolution
2094 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2095 *
2096 * Returns the URI of the resource or NULL if not found
2097 */
2098static xmlChar *
2099xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2100 xmlChar *ret = NULL;
2101 xmlChar *urnID = NULL;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002102
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002103 if (catal == NULL)
2104 return(NULL);
2105 if (URI == NULL)
2106 return(NULL);
2107
2108 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2109 urnID = xmlCatalogUnWrapURN(URI);
2110 if (xmlDebugCatalogs) {
2111 if (urnID == NULL)
2112 xmlGenericError(xmlGenericErrorContext,
2113 "URN ID %s expanded to NULL\n", URI);
2114 else
2115 xmlGenericError(xmlGenericErrorContext,
2116 "URN ID expanded to %s\n", urnID);
2117 }
2118 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2119 if (urnID != NULL)
2120 xmlFree(urnID);
2121 return(ret);
2122 }
2123 while (catal != NULL) {
2124 if (catal->type == XML_CATA_CATALOG) {
2125 if (catal->children == NULL) {
2126 xmlFetchXMLCatalogFile(catal);
2127 }
2128 if (catal->children != NULL) {
2129 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2130 if (ret != NULL)
2131 return(ret);
2132 }
2133 }
2134 catal = catal->next;
2135 }
2136 return(ret);
2137}
2138
Daniel Veillard344cee72001-08-20 00:08:40 +00002139/************************************************************************
2140 * *
2141 * The SGML Catalog parser *
Daniel Veillarda7374592001-05-10 14:17:55 +00002142 * *
2143 ************************************************************************/
2144
2145
2146#define RAW *cur
2147#define NEXT cur++;
2148#define SKIP(x) cur += x;
2149
William M. Brack272693c2003-11-14 16:20:34 +00002150#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002151
Daniel Veillard75b96822001-10-11 18:59:45 +00002152/**
2153 * xmlParseSGMLCatalogComment:
2154 * @cur: the current character
2155 *
2156 * Skip a comment in an SGML catalog
2157 *
2158 * Returns new current character
2159 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002160static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002161xmlParseSGMLCatalogComment(const xmlChar *cur) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002162 if ((cur[0] != '-') || (cur[1] != '-'))
Daniel Veillarda7374592001-05-10 14:17:55 +00002163 return(cur);
2164 SKIP(2);
2165 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2166 NEXT;
2167 if (cur[0] == 0) {
2168 return(NULL);
2169 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002170 return(cur + 2);
Daniel Veillarda7374592001-05-10 14:17:55 +00002171}
2172
Daniel Veillard75b96822001-10-11 18:59:45 +00002173/**
2174 * xmlParseSGMLCatalogPubid:
2175 * @cur: the current character
2176 * @id: the return location
2177 *
2178 * Parse an SGML catalog ID
2179 *
2180 * Returns new current character and store the value in @id
2181 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002182static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002183xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002184 xmlChar *buf = NULL, *tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002185 int len = 0;
2186 int size = 50;
2187 xmlChar stop;
2188 int count = 0;
2189
2190 *id = NULL;
2191
2192 if (RAW == '"') {
2193 NEXT;
2194 stop = '"';
2195 } else if (RAW == '\'') {
2196 NEXT;
2197 stop = '\'';
2198 } else {
2199 stop = ' ';
2200 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002201 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
Daniel Veillarda7374592001-05-10 14:17:55 +00002202 if (buf == NULL) {
Daniel Veillard69d2c172003-10-09 11:46:07 +00002203 xmlCatalogErrMemory("allocating public ID");
Daniel Veillarda7374592001-05-10 14:17:55 +00002204 return(NULL);
2205 }
William M. Brack76e95df2003-10-18 16:20:14 +00002206 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002207 if ((*cur == stop) && (stop != ' '))
2208 break;
William M. Brack76e95df2003-10-18 16:20:14 +00002209 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
Daniel Veillarda7374592001-05-10 14:17:55 +00002210 break;
2211 if (len + 1 >= size) {
2212 size *= 2;
Daniel Veillard69d2c172003-10-09 11:46:07 +00002213 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2214 if (tmp == NULL) {
2215 xmlCatalogErrMemory("allocating public ID");
2216 xmlFree(buf);
Daniel Veillarda7374592001-05-10 14:17:55 +00002217 return(NULL);
2218 }
Daniel Veillard69d2c172003-10-09 11:46:07 +00002219 buf = tmp;
Daniel Veillarda7374592001-05-10 14:17:55 +00002220 }
2221 buf[len++] = *cur;
2222 count++;
2223 NEXT;
2224 }
2225 buf[len] = 0;
2226 if (stop == ' ') {
William M. Brack76e95df2003-10-18 16:20:14 +00002227 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002228 xmlFree(buf);
2229 return(NULL);
2230 }
2231 } else {
2232 if (*cur != stop) {
2233 xmlFree(buf);
2234 return(NULL);
2235 }
2236 NEXT;
2237 }
2238 *id = buf;
2239 return(cur);
2240}
2241
Daniel Veillard75b96822001-10-11 18:59:45 +00002242/**
2243 * xmlParseSGMLCatalogName:
2244 * @cur: the current character
2245 * @name: the return location
2246 *
2247 * Parse an SGML catalog name
2248 *
2249 * Returns new current character and store the value in @name
2250 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002251static const xmlChar *
Daniel Veillardcda96922001-08-21 10:56:31 +00002252xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002253 xmlChar buf[XML_MAX_NAMELEN + 5];
2254 int len = 0;
2255 int c;
2256
2257 *name = NULL;
2258
2259 /*
2260 * Handler for more complex cases
2261 */
2262 c = *cur;
2263 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2264 return(NULL);
2265 }
2266
2267 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2268 (c == '.') || (c == '-') ||
2269 (c == '_') || (c == ':'))) {
2270 buf[len++] = c;
2271 cur++;
2272 c = *cur;
2273 if (len >= XML_MAX_NAMELEN)
2274 return(NULL);
2275 }
2276 *name = xmlStrndup(buf, len);
2277 return(cur);
2278}
2279
Daniel Veillard75b96822001-10-11 18:59:45 +00002280/**
2281 * xmlGetSGMLCatalogEntryType:
2282 * @name: the entry name
2283 *
2284 * Get the Catalog entry type for a given SGML Catalog name
2285 *
2286 * Returns Catalog entry type
2287 */
Daniel Veillard344cee72001-08-20 00:08:40 +00002288static xmlCatalogEntryType
Daniel Veillardcda96922001-08-21 10:56:31 +00002289xmlGetSGMLCatalogEntryType(const xmlChar *name) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002290 xmlCatalogEntryType type = XML_CATA_NONE;
2291 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2292 type = SGML_CATA_SYSTEM;
2293 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2294 type = SGML_CATA_PUBLIC;
2295 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2296 type = SGML_CATA_DELEGATE;
2297 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2298 type = SGML_CATA_ENTITY;
2299 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2300 type = SGML_CATA_DOCTYPE;
2301 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2302 type = SGML_CATA_LINKTYPE;
2303 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2304 type = SGML_CATA_NOTATION;
2305 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2306 type = SGML_CATA_SGMLDECL;
2307 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2308 type = SGML_CATA_DOCUMENT;
2309 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2310 type = SGML_CATA_CATALOG;
2311 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2312 type = SGML_CATA_BASE;
Daniel Veillard344cee72001-08-20 00:08:40 +00002313 return(type);
2314}
2315
Daniel Veillard75b96822001-10-11 18:59:45 +00002316/**
2317 * xmlParseSGMLCatalog:
2318 * @catal: the SGML Catalog
2319 * @value: the content of the SGML Catalog serialization
2320 * @file: the filepath for the catalog
2321 * @super: should this be handled as a Super Catalog in which case
2322 * parsing is not recursive
2323 *
2324 * Parse an SGML catalog content and fill up the @catal hash table with
2325 * the new entries found.
2326 *
2327 * Returns 0 in case of success, -1 in case of error.
2328 */
Daniel Veillarda7374592001-05-10 14:17:55 +00002329static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002330xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2331 const char *file, int super) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002332 const xmlChar *cur = value;
2333 xmlChar *base = NULL;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002334 int res;
Daniel Veillarda7374592001-05-10 14:17:55 +00002335
2336 if ((cur == NULL) || (file == NULL))
2337 return(-1);
2338 base = xmlStrdup((const xmlChar *) file);
2339
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002340 while ((cur != NULL) && (cur[0] != 0)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002341 SKIP_BLANKS;
Daniel Veillardbc2ddbe2001-08-23 10:24:27 +00002342 if (cur[0] == 0)
2343 break;
Daniel Veillarda7374592001-05-10 14:17:55 +00002344 if ((cur[0] == '-') && (cur[1] == '-')) {
Daniel Veillardcda96922001-08-21 10:56:31 +00002345 cur = xmlParseSGMLCatalogComment(cur);
Daniel Veillarda7374592001-05-10 14:17:55 +00002346 if (cur == NULL) {
2347 /* error */
2348 break;
2349 }
2350 } else {
2351 xmlChar *sysid = NULL;
2352 xmlChar *name = NULL;
2353 xmlCatalogEntryType type = XML_CATA_NONE;
2354
Daniel Veillardcda96922001-08-21 10:56:31 +00002355 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002356 if (name == NULL) {
2357 /* error */
2358 break;
2359 }
William M. Brack76e95df2003-10-18 16:20:14 +00002360 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002361 /* error */
2362 break;
2363 }
2364 SKIP_BLANKS;
2365 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002366 type = SGML_CATA_SYSTEM;
Daniel Veillarda7374592001-05-10 14:17:55 +00002367 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002368 type = SGML_CATA_PUBLIC;
Daniel Veillarda7374592001-05-10 14:17:55 +00002369 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002370 type = SGML_CATA_DELEGATE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002371 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002372 type = SGML_CATA_ENTITY;
Daniel Veillarda7374592001-05-10 14:17:55 +00002373 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002374 type = SGML_CATA_DOCTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002375 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002376 type = SGML_CATA_LINKTYPE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002377 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002378 type = SGML_CATA_NOTATION;
Daniel Veillarda7374592001-05-10 14:17:55 +00002379 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002380 type = SGML_CATA_SGMLDECL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002381 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002382 type = SGML_CATA_DOCUMENT;
Daniel Veillarda7374592001-05-10 14:17:55 +00002383 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002384 type = SGML_CATA_CATALOG;
Daniel Veillarda7374592001-05-10 14:17:55 +00002385 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
Daniel Veillard344cee72001-08-20 00:08:40 +00002386 type = SGML_CATA_BASE;
Daniel Veillarda7374592001-05-10 14:17:55 +00002387 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2388 xmlFree(name);
Daniel Veillardcda96922001-08-21 10:56:31 +00002389 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002390 if (name == NULL) {
2391 /* error */
2392 break;
2393 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002394 xmlFree(name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002395 continue;
2396 }
2397 xmlFree(name);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002398 name = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00002399
2400 switch(type) {
Daniel Veillard344cee72001-08-20 00:08:40 +00002401 case SGML_CATA_ENTITY:
Daniel Veillarda7374592001-05-10 14:17:55 +00002402 if (*cur == '%')
Daniel Veillard344cee72001-08-20 00:08:40 +00002403 type = SGML_CATA_PENTITY;
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +02002404 /* Falls through. */
Daniel Veillard344cee72001-08-20 00:08:40 +00002405 case SGML_CATA_PENTITY:
2406 case SGML_CATA_DOCTYPE:
2407 case SGML_CATA_LINKTYPE:
2408 case SGML_CATA_NOTATION:
Daniel Veillardcda96922001-08-21 10:56:31 +00002409 cur = xmlParseSGMLCatalogName(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002410 if (cur == NULL) {
2411 /* error */
2412 break;
2413 }
William M. Brack76e95df2003-10-18 16:20:14 +00002414 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002415 /* error */
2416 break;
2417 }
2418 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002419 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002420 if (cur == NULL) {
2421 /* error */
2422 break;
2423 }
2424 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002425 case SGML_CATA_PUBLIC:
2426 case SGML_CATA_SYSTEM:
2427 case SGML_CATA_DELEGATE:
Daniel Veillardcda96922001-08-21 10:56:31 +00002428 cur = xmlParseSGMLCatalogPubid(cur, &name);
Daniel Veillarda7374592001-05-10 14:17:55 +00002429 if (cur == NULL) {
2430 /* error */
2431 break;
2432 }
Daniel Veillardc8155052004-07-16 09:03:08 +00002433 if (type != SGML_CATA_SYSTEM) {
2434 xmlChar *normid;
2435
2436 normid = xmlCatalogNormalizePublic(name);
2437 if (normid != NULL) {
2438 if (name != NULL)
2439 xmlFree(name);
2440 if (*normid != 0)
2441 name = normid;
2442 else {
2443 xmlFree(normid);
2444 name = NULL;
2445 }
2446 }
2447 }
William M. Brack76e95df2003-10-18 16:20:14 +00002448 if (!IS_BLANK_CH(*cur)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002449 /* error */
2450 break;
2451 }
2452 SKIP_BLANKS;
Daniel Veillardcda96922001-08-21 10:56:31 +00002453 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002454 if (cur == NULL) {
2455 /* error */
2456 break;
2457 }
2458 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002459 case SGML_CATA_BASE:
2460 case SGML_CATA_CATALOG:
2461 case SGML_CATA_DOCUMENT:
2462 case SGML_CATA_SGMLDECL:
Daniel Veillardcda96922001-08-21 10:56:31 +00002463 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002464 if (cur == NULL) {
2465 /* error */
2466 break;
2467 }
2468 break;
2469 default:
2470 break;
2471 }
2472 if (cur == NULL) {
2473 if (name != NULL)
2474 xmlFree(name);
2475 if (sysid != NULL)
2476 xmlFree(sysid);
2477 break;
Daniel Veillard344cee72001-08-20 00:08:40 +00002478 } else if (type == SGML_CATA_BASE) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002479 if (base != NULL)
2480 xmlFree(base);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002481 base = xmlStrdup(sysid);
Daniel Veillard344cee72001-08-20 00:08:40 +00002482 } else if ((type == SGML_CATA_PUBLIC) ||
2483 (type == SGML_CATA_SYSTEM)) {
Daniel Veillarda7374592001-05-10 14:17:55 +00002484 xmlChar *filename;
2485
2486 filename = xmlBuildURI(sysid, base);
2487 if (filename != NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002488 xmlCatalogEntryPtr entry;
Daniel Veillarda7374592001-05-10 14:17:55 +00002489
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002490 entry = xmlNewCatalogEntry(type, name, filename,
William M. Brackb7b54de2004-10-06 16:38:01 +00002491 NULL, XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002492 res = xmlHashAddEntry(catal->sgml, name, entry);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002493 if (res < 0) {
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01002494 xmlFreeCatalogEntry(entry, NULL);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002495 }
2496 xmlFree(filename);
Daniel Veillarda7374592001-05-10 14:17:55 +00002497 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002498
Daniel Veillard344cee72001-08-20 00:08:40 +00002499 } else if (type == SGML_CATA_CATALOG) {
Daniel Veillard82d75332001-10-08 15:01:59 +00002500 if (super) {
2501 xmlCatalogEntryPtr entry;
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002502
Daniel Veillardc853b322001-11-06 15:24:37 +00002503 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002504 XML_CATA_PREFER_NONE, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002505 res = xmlHashAddEntry(catal->sgml, sysid, entry);
Daniel Veillard82d75332001-10-08 15:01:59 +00002506 if (res < 0) {
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01002507 xmlFreeCatalogEntry(entry, NULL);
Daniel Veillard82d75332001-10-08 15:01:59 +00002508 }
2509 } else {
2510 xmlChar *filename;
2511
2512 filename = xmlBuildURI(sysid, base);
2513 if (filename != NULL) {
Daniel Veillard75b96822001-10-11 18:59:45 +00002514 xmlExpandCatalog(catal, (const char *)filename);
Daniel Veillard82d75332001-10-08 15:01:59 +00002515 xmlFree(filename);
2516 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002517 }
Daniel Veillarda7374592001-05-10 14:17:55 +00002518 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00002519 /*
2520 * drop anything else we won't handle it
2521 */
2522 if (name != NULL)
2523 xmlFree(name);
2524 if (sysid != NULL)
2525 xmlFree(sysid);
Daniel Veillarda7374592001-05-10 14:17:55 +00002526 }
2527 }
2528 if (base != NULL)
2529 xmlFree(base);
2530 if (cur == NULL)
2531 return(-1);
2532 return(0);
2533}
2534
Daniel Veillard75b96822001-10-11 18:59:45 +00002535/************************************************************************
2536 * *
2537 * SGML Catalog handling *
2538 * *
2539 ************************************************************************/
2540
Daniel Veillardcda96922001-08-21 10:56:31 +00002541/**
2542 * xmlCatalogGetSGMLPublic:
2543 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002544 * @pubID: the public ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002545 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002546 * Try to lookup the catalog local reference associated to a public ID
Daniel Veillardcda96922001-08-21 10:56:31 +00002547 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002548 * Returns the local resource if found or NULL otherwise.
Daniel Veillardcda96922001-08-21 10:56:31 +00002549 */
2550static const xmlChar *
2551xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2552 xmlCatalogEntryPtr entry;
Daniel Veillardc8155052004-07-16 09:03:08 +00002553 xmlChar *normid;
Daniel Veillardcda96922001-08-21 10:56:31 +00002554
2555 if (catal == NULL)
2556 return(NULL);
2557
Daniel Veillardc8155052004-07-16 09:03:08 +00002558 normid = xmlCatalogNormalizePublic(pubID);
2559 if (normid != NULL)
2560 pubID = (*normid != 0 ? normid : NULL);
2561
Daniel Veillardcda96922001-08-21 10:56:31 +00002562 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
Daniel Veillardc8155052004-07-16 09:03:08 +00002563 if (entry == NULL) {
2564 if (normid != NULL)
2565 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002566 return(NULL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002567 }
2568 if (entry->type == SGML_CATA_PUBLIC) {
2569 if (normid != NULL)
2570 xmlFree(normid);
Daniel Veillardc853b322001-11-06 15:24:37 +00002571 return(entry->URL);
Daniel Veillardc8155052004-07-16 09:03:08 +00002572 }
2573 if (normid != NULL)
2574 xmlFree(normid);
Daniel Veillardcda96922001-08-21 10:56:31 +00002575 return(NULL);
2576}
2577
2578/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002579 * xmlCatalogGetSGMLSystem:
2580 * @catal: an SGML catalog hash
Daniel Veillard06d25242004-02-25 13:01:42 +00002581 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002582 *
2583 * Try to lookup the catalog local reference for a system ID
2584 *
Daniel Veillard770075b2004-02-25 10:44:30 +00002585 * Returns the local resource if found or NULL otherwise.
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002586 */
2587static const xmlChar *
2588xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2589 xmlCatalogEntryPtr entry;
2590
2591 if (catal == NULL)
2592 return(NULL);
2593
2594 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2595 if (entry == NULL)
2596 return(NULL);
2597 if (entry->type == SGML_CATA_SYSTEM)
Daniel Veillardc853b322001-11-06 15:24:37 +00002598 return(entry->URL);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002599 return(NULL);
2600}
2601
2602/**
Daniel Veillardcda96922001-08-21 10:56:31 +00002603 * xmlCatalogSGMLResolve:
Daniel Veillard75b96822001-10-11 18:59:45 +00002604 * @catal: the SGML catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002605 * @pubID: the public ID string
2606 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00002607 *
2608 * Do a complete resolution lookup of an External Identifier
2609 *
2610 * Returns the URI of the resource or NULL if not found
2611 */
2612static const xmlChar *
Daniel Veillard75b96822001-10-11 18:59:45 +00002613xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2614 const xmlChar *sysID) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002615 const xmlChar *ret = NULL;
2616
Daniel Veillard75b96822001-10-11 18:59:45 +00002617 if (catal->sgml == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002618 return(NULL);
2619
2620 if (pubID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002621 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002622 if (ret != NULL)
2623 return(ret);
2624 if (sysID != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00002625 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
Daniel Veillard63806b52008-06-10 14:56:11 +00002626 if (ret != NULL)
2627 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00002628 return(NULL);
2629}
2630
Daniel Veillarda7374592001-05-10 14:17:55 +00002631/************************************************************************
2632 * *
Daniel Veillard75b96822001-10-11 18:59:45 +00002633 * Specific Public interfaces *
2634 * *
2635 ************************************************************************/
2636
2637/**
2638 * xmlLoadSGMLSuperCatalog:
2639 * @filename: a file path
2640 *
2641 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2642 * references. This is only needed for manipulating SGML Super Catalogs
2643 * like adding and removing CATALOG or DELEGATE entries.
2644 *
2645 * Returns the catalog parsed or NULL in case of error
2646 */
2647xmlCatalogPtr
2648xmlLoadSGMLSuperCatalog(const char *filename)
2649{
2650 xmlChar *content;
2651 xmlCatalogPtr catal;
2652 int ret;
2653
2654 content = xmlLoadFileContent(filename);
2655 if (content == NULL)
2656 return(NULL);
2657
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002658 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002659 if (catal == NULL) {
2660 xmlFree(content);
2661 return(NULL);
2662 }
2663
2664 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2665 xmlFree(content);
2666 if (ret < 0) {
2667 xmlFreeCatalog(catal);
2668 return(NULL);
2669 }
2670 return (catal);
2671}
2672
2673/**
2674 * xmlLoadACatalog:
2675 * @filename: a file path
2676 *
2677 * Load the catalog and build the associated data structures.
2678 * This can be either an XML Catalog or an SGML Catalog
2679 * It will recurse in SGML CATALOG entries. On the other hand XML
2680 * Catalogs are not handled recursively.
2681 *
2682 * Returns the catalog parsed or NULL in case of error
2683 */
2684xmlCatalogPtr
2685xmlLoadACatalog(const char *filename)
2686{
2687 xmlChar *content;
2688 xmlChar *first;
2689 xmlCatalogPtr catal;
2690 int ret;
2691
2692 content = xmlLoadFileContent(filename);
2693 if (content == NULL)
2694 return(NULL);
2695
2696
2697 first = content;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002698
Daniel Veillard75b96822001-10-11 18:59:45 +00002699 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2700 (!(((*first >= 'A') && (*first <= 'Z')) ||
2701 ((*first >= 'a') && (*first <= 'z')))))
2702 first++;
2703
2704 if (*first != '<') {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002705 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002706 if (catal == NULL) {
2707 xmlFree(content);
2708 return(NULL);
2709 }
2710 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2711 if (ret < 0) {
2712 xmlFreeCatalog(catal);
2713 xmlFree(content);
2714 return(NULL);
2715 }
2716 } else {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002717 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
Daniel Veillard75b96822001-10-11 18:59:45 +00002718 if (catal == NULL) {
2719 xmlFree(content);
2720 return(NULL);
2721 }
Daniel Veillardc853b322001-11-06 15:24:37 +00002722 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002723 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002724 }
2725 xmlFree(content);
2726 return (catal);
2727}
2728
2729/**
2730 * xmlExpandCatalog:
2731 * @catal: a catalog
2732 * @filename: a file path
2733 *
2734 * Load the catalog and expand the existing catal structure.
2735 * This can be either an XML Catalog or an SGML Catalog
2736 *
2737 * Returns 0 in case of success, -1 in case of error
2738 */
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002739static int
Daniel Veillard75b96822001-10-11 18:59:45 +00002740xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2741{
Daniel Veillard75b96822001-10-11 18:59:45 +00002742 int ret;
2743
2744 if ((catal == NULL) || (filename == NULL))
2745 return(-1);
2746
Daniel Veillard75b96822001-10-11 18:59:45 +00002747
2748 if (catal->type == XML_SGML_CATALOG_TYPE) {
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002749 xmlChar *content;
2750
2751 content = xmlLoadFileContent(filename);
2752 if (content == NULL)
2753 return(-1);
2754
Daniel Veillard75b96822001-10-11 18:59:45 +00002755 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2756 if (ret < 0) {
2757 xmlFree(content);
2758 return(-1);
2759 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00002760 xmlFree(content);
Daniel Veillard75b96822001-10-11 18:59:45 +00002761 } else {
2762 xmlCatalogEntryPtr tmp, cur;
Daniel Veillardc853b322001-11-06 15:24:37 +00002763 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002764 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00002765
Daniel Veillard75b96822001-10-11 18:59:45 +00002766 cur = catal->xml;
2767 if (cur == NULL) {
2768 catal->xml = tmp;
2769 } else {
2770 while (cur->next != NULL) cur = cur->next;
2771 cur->next = tmp;
2772 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002773 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002774 return (0);
2775}
2776
2777/**
2778 * xmlACatalogResolveSystem:
2779 * @catal: a Catalog
Daniel Veillard06d25242004-02-25 13:01:42 +00002780 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002781 *
2782 * Try to lookup the catalog resource for a system ID
2783 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002784 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002785 * must be freed by the caller.
2786 */
2787xmlChar *
2788xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2789 xmlChar *ret = NULL;
2790
2791 if ((sysID == NULL) || (catal == NULL))
2792 return(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002793
Daniel Veillard75b96822001-10-11 18:59:45 +00002794 if (xmlDebugCatalogs)
2795 xmlGenericError(xmlGenericErrorContext,
2796 "Resolve sysID %s\n", sysID);
2797
2798 if (catal->type == XML_XML_CATALOG_TYPE) {
2799 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2800 if (ret == XML_CATAL_BREAK)
2801 ret = NULL;
2802 } else {
2803 const xmlChar *sgml;
2804
2805 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2806 if (sgml != NULL)
2807 ret = xmlStrdup(sgml);
2808 }
2809 return(ret);
2810}
2811
2812/**
2813 * xmlACatalogResolvePublic:
2814 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002815 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002816 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002817 * Try to lookup the catalog local reference associated to a public ID in that catalog
Daniel Veillard75b96822001-10-11 18:59:45 +00002818 *
Daniel Veillard06d25242004-02-25 13:01:42 +00002819 * Returns the local resource if found or NULL otherwise, the value returned
Daniel Veillard75b96822001-10-11 18:59:45 +00002820 * must be freed by the caller.
2821 */
2822xmlChar *
2823xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2824 xmlChar *ret = NULL;
2825
2826 if ((pubID == NULL) || (catal == NULL))
2827 return(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002828
Daniel Veillard75b96822001-10-11 18:59:45 +00002829 if (xmlDebugCatalogs)
2830 xmlGenericError(xmlGenericErrorContext,
2831 "Resolve pubID %s\n", pubID);
2832
2833 if (catal->type == XML_XML_CATALOG_TYPE) {
2834 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2835 if (ret == XML_CATAL_BREAK)
2836 ret = NULL;
2837 } else {
2838 const xmlChar *sgml;
2839
2840 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2841 if (sgml != NULL)
2842 ret = xmlStrdup(sgml);
2843 }
2844 return(ret);
2845}
2846
2847/**
2848 * xmlACatalogResolve:
2849 * @catal: a Catalog
Daniel Veillard5aad8322002-12-11 15:59:44 +00002850 * @pubID: the public ID string
2851 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00002852 *
2853 * Do a complete resolution lookup of an External Identifier
2854 *
2855 * Returns the URI of the resource or NULL if not found, it must be freed
2856 * by the caller.
2857 */
2858xmlChar *
2859xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2860 const xmlChar * sysID)
2861{
2862 xmlChar *ret = NULL;
2863
2864 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2865 return (NULL);
2866
2867 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002868 if ((pubID != NULL) && (sysID != NULL)) {
2869 xmlGenericError(xmlGenericErrorContext,
2870 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2871 } else if (pubID != NULL) {
2872 xmlGenericError(xmlGenericErrorContext,
2873 "Resolve: pubID %s\n", pubID);
2874 } else {
2875 xmlGenericError(xmlGenericErrorContext,
2876 "Resolve: sysID %s\n", sysID);
2877 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002878 }
2879
2880 if (catal->type == XML_XML_CATALOG_TYPE) {
2881 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2882 if (ret == XML_CATAL_BREAK)
2883 ret = NULL;
2884 } else {
2885 const xmlChar *sgml;
2886
2887 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2888 if (sgml != NULL)
2889 ret = xmlStrdup(sgml);
2890 }
2891 return (ret);
2892}
2893
2894/**
2895 * xmlACatalogResolveURI:
2896 * @catal: a Catalog
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002897 * @URI: the URI
Daniel Veillard75b96822001-10-11 18:59:45 +00002898 *
2899 * Do a complete resolution lookup of an URI
2900 *
2901 * Returns the URI of the resource or NULL if not found, it must be freed
2902 * by the caller.
2903 */
2904xmlChar *
2905xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2906 xmlChar *ret = NULL;
2907
2908 if ((URI == NULL) || (catal == NULL))
2909 return(NULL);
2910
Daniel Veillardb44025c2001-10-11 22:55:55 +00002911 if (xmlDebugCatalogs)
Daniel Veillard75b96822001-10-11 18:59:45 +00002912 xmlGenericError(xmlGenericErrorContext,
2913 "Resolve URI %s\n", URI);
2914
2915 if (catal->type == XML_XML_CATALOG_TYPE) {
2916 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2917 if (ret == XML_CATAL_BREAK)
2918 ret = NULL;
2919 } else {
2920 const xmlChar *sgml;
2921
2922 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2923 if (sgml != NULL)
Daniel Veillard63806b52008-06-10 14:56:11 +00002924 ret = xmlStrdup(sgml);
Daniel Veillard75b96822001-10-11 18:59:45 +00002925 }
2926 return(ret);
2927}
2928
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002929#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard75b96822001-10-11 18:59:45 +00002930/**
2931 * xmlACatalogDump:
2932 * @catal: a Catalog
2933 * @out: the file.
2934 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00002935 * Dump the given catalog to the given file.
Daniel Veillard75b96822001-10-11 18:59:45 +00002936 */
2937void
2938xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002939 if ((out == NULL) || (catal == NULL))
Daniel Veillard75b96822001-10-11 18:59:45 +00002940 return;
2941
2942 if (catal->type == XML_XML_CATALOG_TYPE) {
2943 xmlDumpXMLCatalog(out, catal->xml);
2944 } else {
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01002945 xmlHashScan(catal->sgml, xmlCatalogDumpEntry, out);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002946 }
Daniel Veillard75b96822001-10-11 18:59:45 +00002947}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002948#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard75b96822001-10-11 18:59:45 +00002949
2950/**
2951 * xmlACatalogAdd:
2952 * @catal: a Catalog
2953 * @type: the type of record to add to the catalog
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002954 * @orig: the system, public or prefix to match
Daniel Veillard75b96822001-10-11 18:59:45 +00002955 * @replace: the replacement value for the match
2956 *
2957 * Add an entry in the catalog, it may overwrite existing but
2958 * different entries.
2959 *
2960 * Returns 0 if successful, -1 otherwise
2961 */
2962int
2963xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2964 const xmlChar * orig, const xmlChar * replace)
2965{
2966 int res = -1;
2967
2968 if (catal == NULL)
2969 return(-1);
2970
2971 if (catal->type == XML_XML_CATALOG_TYPE) {
2972 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2973 } else {
2974 xmlCatalogEntryType cattype;
2975
2976 cattype = xmlGetSGMLCatalogEntryType(type);
2977 if (cattype != XML_CATA_NONE) {
2978 xmlCatalogEntryPtr entry;
2979
Daniel Veillardc853b322001-11-06 15:24:37 +00002980 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00002981 XML_CATA_PREFER_NONE, NULL);
Daniel Veillardcd21dc72001-11-04 20:03:38 +00002982 if (catal->sgml == NULL)
2983 catal->sgml = xmlHashCreate(10);
Daniel Veillard75b96822001-10-11 18:59:45 +00002984 res = xmlHashAddEntry(catal->sgml, orig, entry);
2985 }
2986 }
2987 return (res);
2988}
2989
2990/**
2991 * xmlACatalogRemove:
2992 * @catal: a Catalog
2993 * @value: the value to remove
2994 *
2995 * Remove an entry from the catalog
2996 *
2997 * Returns the number of entries removed if successful, -1 otherwise
2998 */
2999int
3000xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
3001 int res = -1;
3002
3003 if ((catal == NULL) || (value == NULL))
3004 return(-1);
3005
3006 if (catal->type == XML_XML_CATALOG_TYPE) {
3007 res = xmlDelXMLCatalog(catal->xml, value);
3008 } else {
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01003009 res = xmlHashRemoveEntry(catal->sgml, value, xmlFreeCatalogEntry);
Daniel Veillard75b96822001-10-11 18:59:45 +00003010 if (res == 0)
3011 res = 1;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003012 }
Daniel Veillard75b96822001-10-11 18:59:45 +00003013 return(res);
3014}
3015
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003016/**
3017 * xmlNewCatalog:
3018 * @sgml: should this create an SGML catalog
3019 *
3020 * create a new Catalog.
3021 *
3022 * Returns the xmlCatalogPtr or NULL in case of error
3023 */
3024xmlCatalogPtr
3025xmlNewCatalog(int sgml) {
3026 xmlCatalogPtr catal = NULL;
3027
3028 if (sgml) {
3029 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
3030 xmlCatalogDefaultPrefer);
3031 if ((catal != NULL) && (catal->sgml == NULL))
3032 catal->sgml = xmlHashCreate(10);
3033 } else
3034 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3035 xmlCatalogDefaultPrefer);
3036 return(catal);
3037}
3038
3039/**
3040 * xmlCatalogIsEmpty:
3041 * @catal: should this create an SGML catalog
3042 *
3043 * Check is a catalog is empty
3044 *
3045 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3046 */
3047int
3048xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3049 if (catal == NULL)
3050 return(-1);
3051
3052 if (catal->type == XML_XML_CATALOG_TYPE) {
3053 if (catal->xml == NULL)
3054 return(1);
3055 if ((catal->xml->type != XML_CATA_CATALOG) &&
3056 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3057 return(-1);
3058 if (catal->xml->children == NULL)
3059 return(1);
3060 return(0);
3061 } else {
3062 int res;
3063
3064 if (catal->sgml == NULL)
3065 return(1);
3066 res = xmlHashSize(catal->sgml);
3067 if (res == 0)
3068 return(1);
3069 if (res < 0)
3070 return(-1);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003071 }
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003072 return(0);
3073}
3074
Daniel Veillard75b96822001-10-11 18:59:45 +00003075/************************************************************************
3076 * *
3077 * Public interfaces manipulating the global shared default catalog *
Daniel Veillarda7374592001-05-10 14:17:55 +00003078 * *
3079 ************************************************************************/
3080
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003081/**
Daniel Veillard81463942001-10-16 12:34:39 +00003082 * xmlInitializeCatalogData:
3083 *
3084 * Do the catalog initialization only of global data, doesn't try to load
3085 * any catalog actually.
3086 * this function is not thread safe, catalog initialization should
3087 * preferably be done once at startup
3088 */
3089static void
3090xmlInitializeCatalogData(void) {
3091 if (xmlCatalogInitialized != 0)
3092 return;
3093
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003094 if (getenv("XML_DEBUG_CATALOG"))
Daniel Veillard81463942001-10-16 12:34:39 +00003095 xmlDebugCatalogs = 1;
3096 xmlCatalogMutex = xmlNewRMutex();
3097
3098 xmlCatalogInitialized = 1;
3099}
3100/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003101 * xmlInitializeCatalog:
3102 *
3103 * Do the catalog initialization.
Daniel Veillard81463942001-10-16 12:34:39 +00003104 * this function is not thread safe, catalog initialization should
3105 * preferably be done once at startup
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003106 */
3107void
3108xmlInitializeCatalog(void) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003109 if (xmlCatalogInitialized != 0)
3110 return;
3111
Daniel Veillard81463942001-10-16 12:34:39 +00003112 xmlInitializeCatalogData();
3113 xmlRMutexLock(xmlCatalogMutex);
3114
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003115 if (getenv("XML_DEBUG_CATALOG"))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003116 xmlDebugCatalogs = 1;
Daniel Veillard81463942001-10-16 12:34:39 +00003117
Daniel Veillard75b96822001-10-11 18:59:45 +00003118 if (xmlDefaultCatalog == NULL) {
3119 const char *catalogs;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003120 char *path;
3121 const char *cur, *paths;
Daniel Veillard75b96822001-10-11 18:59:45 +00003122 xmlCatalogPtr catal;
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003123 xmlCatalogEntryPtr *nextent;
Daniel Veillard75b96822001-10-11 18:59:45 +00003124
Daniel Veillardb44025c2001-10-11 22:55:55 +00003125 catalogs = (const char *) getenv("XML_CATALOG_FILES");
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003126 if (catalogs == NULL)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003127#if defined(_WIN32) && defined(_MSC_VER)
3128 {
3129 void* hmodule;
3130 hmodule = GetModuleHandleA("libxml2.dll");
3131 if (hmodule == NULL)
3132 hmodule = GetModuleHandleA(NULL);
3133 if (hmodule != NULL) {
3134 char buf[256];
3135 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3136 if (len != 0) {
3137 char* p = &(buf[len]);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003138 while (*p != '\\' && p > buf)
Daniel Veillardfb382b82004-06-14 12:13:12 +00003139 p--;
3140 if (p != buf) {
3141 xmlChar* uri;
3142 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
Denis Pauke1631e12013-03-10 12:47:37 +02003143 uri = xmlCanonicPath((const xmlChar*)buf);
Daniel Veillardfb382b82004-06-14 12:13:12 +00003144 if (uri != NULL) {
3145 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3146 xmlFree(uri);
3147 }
3148 }
3149 }
3150 }
3151 catalogs = XML_XML_DEFAULT_CATALOG;
3152 }
3153#else
Daniel Veillard75b96822001-10-11 18:59:45 +00003154 catalogs = XML_XML_DEFAULT_CATALOG;
Daniel Veillardfb382b82004-06-14 12:13:12 +00003155#endif
Daniel Veillard75b96822001-10-11 18:59:45 +00003156
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003157 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003158 xmlCatalogDefaultPrefer);
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003159 if (catal != NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003160 /* the XML_CATALOG_FILES envvar is allowed to contain a
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003161 space-separated list of entries. */
3162 cur = catalogs;
3163 nextent = &catal->xml;
3164 while (*cur != '\0') {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003165 while (xmlIsBlank_ch(*cur))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003166 cur++;
3167 if (*cur != 0) {
3168 paths = cur;
William M. Brack68aca052003-10-11 15:22:13 +00003169 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003170 cur++;
Daniel Veillarde645e8c2002-10-22 17:35:37 +00003171 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003172 if (path != NULL) {
3173 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003174 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
Igor Zlatkovic124ec312002-10-04 13:32:49 +00003175 if (*nextent != NULL)
3176 nextent = &((*nextent)->next);
3177 xmlFree(path);
3178 }
3179 }
3180 }
Daniel Veillard85c11fa2001-10-16 21:03:08 +00003181 xmlDefaultCatalog = catal;
3182 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003183 }
3184
Daniel Veillard81463942001-10-16 12:34:39 +00003185 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003186}
3187
Daniel Veillard82d75332001-10-08 15:01:59 +00003188
3189/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003190 * xmlLoadCatalog:
3191 * @filename: a file path
3192 *
Daniel Veillard81418e32001-05-22 15:08:55 +00003193 * Load the catalog and makes its definitions effective for the default
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003194 * external entity loader. It will recurse in SGML CATALOG entries.
Daniel Veillard81463942001-10-16 12:34:39 +00003195 * this function is not thread safe, catalog initialization should
3196 * preferably be done once at startup
Daniel Veillarda7374592001-05-10 14:17:55 +00003197 *
3198 * Returns 0 in case of success -1 in case of error
3199 */
3200int
Daniel Veillard16756b62001-10-01 07:36:25 +00003201xmlLoadCatalog(const char *filename)
3202{
Daniel Veillard75b96822001-10-11 18:59:45 +00003203 int ret;
3204 xmlCatalogPtr catal;
Daniel Veillard16756b62001-10-01 07:36:25 +00003205
Daniel Veillard81463942001-10-16 12:34:39 +00003206 if (!xmlCatalogInitialized)
3207 xmlInitializeCatalogData();
3208
3209 xmlRMutexLock(xmlCatalogMutex);
3210
Daniel Veillard75b96822001-10-11 18:59:45 +00003211 if (xmlDefaultCatalog == NULL) {
3212 catal = xmlLoadACatalog(filename);
William M. Brack59002e72003-07-04 17:01:59 +00003213 if (catal == NULL) {
3214 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003215 return(-1);
William M. Brack59002e72003-07-04 17:01:59 +00003216 }
Daniel Veillarda7374592001-05-10 14:17:55 +00003217
Daniel Veillard75b96822001-10-11 18:59:45 +00003218 xmlDefaultCatalog = catal;
Daniel Veillard81463942001-10-16 12:34:39 +00003219 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003220 return(0);
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003221 }
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00003222
Daniel Veillard75b96822001-10-11 18:59:45 +00003223 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
Daniel Veillard81463942001-10-16 12:34:39 +00003224 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003225 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003226}
3227
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003228/**
Daniel Veillard81418e32001-05-22 15:08:55 +00003229 * xmlLoadCatalogs:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003230 * @pathss: a list of directories separated by a colon or a space.
Daniel Veillard81418e32001-05-22 15:08:55 +00003231 *
3232 * Load the catalogs and makes their definitions effective for the default
3233 * external entity loader.
Daniel Veillard81463942001-10-16 12:34:39 +00003234 * this function is not thread safe, catalog initialization should
3235 * preferably be done once at startup
Daniel Veillard81418e32001-05-22 15:08:55 +00003236 */
3237void
3238xmlLoadCatalogs(const char *pathss) {
3239 const char *cur;
3240 const char *paths;
3241 xmlChar *path;
Daniel Veillarded121382007-04-17 12:33:19 +00003242#ifdef _WIN32
3243 int i, iLen;
3244#endif
Daniel Veillard81418e32001-05-22 15:08:55 +00003245
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003246 if (pathss == NULL)
3247 return;
3248
Daniel Veillard81418e32001-05-22 15:08:55 +00003249 cur = pathss;
Daniel Veillard2728f842006-03-09 16:49:24 +00003250 while (*cur != 0) {
William M. Brack68aca052003-10-11 15:22:13 +00003251 while (xmlIsBlank_ch(*cur)) cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003252 if (*cur != 0) {
3253 paths = cur;
Jan Pokorný9811ce72016-04-13 16:56:06 +02003254 while ((*cur != 0) && (*cur != PATH_SEPARATOR) && (!xmlIsBlank_ch(*cur)))
Daniel Veillard81418e32001-05-22 15:08:55 +00003255 cur++;
3256 path = xmlStrndup((const xmlChar *)paths, cur - paths);
Daniel Veillarded121382007-04-17 12:33:19 +00003257#ifdef _WIN32
Denis Pauke1631e12013-03-10 12:47:37 +02003258 iLen = strlen((const char*)path);
Daniel Veillarded121382007-04-17 12:33:19 +00003259 for(i = 0; i < iLen; i++) {
3260 if(path[i] == '\\') {
3261 path[i] = '/';
3262 }
3263 }
3264#endif
Daniel Veillard81418e32001-05-22 15:08:55 +00003265 if (path != NULL) {
3266 xmlLoadCatalog((const char *) path);
3267 xmlFree(path);
3268 }
3269 }
Jan Pokorný9811ce72016-04-13 16:56:06 +02003270 while (*cur == PATH_SEPARATOR)
Igor Zlatkovic130e5792002-11-06 22:51:58 +00003271 cur++;
Daniel Veillard81418e32001-05-22 15:08:55 +00003272 }
3273}
3274
Daniel Veillarda7374592001-05-10 14:17:55 +00003275/**
3276 * xmlCatalogCleanup:
3277 *
3278 * Free up all the memory associated with catalogs
3279 */
3280void
3281xmlCatalogCleanup(void) {
Daniel Veillard364789a2001-10-16 12:45:00 +00003282 if (xmlCatalogInitialized == 0)
3283 return;
3284
Daniel Veillard81463942001-10-16 12:34:39 +00003285 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003286 if (xmlDebugCatalogs)
3287 xmlGenericError(xmlGenericErrorContext,
3288 "Catalogs cleanup\n");
Daniel Veillard6990bf32001-08-23 21:17:48 +00003289 if (xmlCatalogXMLFiles != NULL)
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01003290 xmlHashFree(xmlCatalogXMLFiles, xmlFreeCatalogHashEntryList);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003291 xmlCatalogXMLFiles = NULL;
Daniel Veillarda7374592001-05-10 14:17:55 +00003292 if (xmlDefaultCatalog != NULL)
Daniel Veillard75b96822001-10-11 18:59:45 +00003293 xmlFreeCatalog(xmlDefaultCatalog);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003294 xmlDefaultCatalog = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003295 xmlDebugCatalogs = 0;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003296 xmlCatalogInitialized = 0;
Daniel Veillard81463942001-10-16 12:34:39 +00003297 xmlRMutexUnlock(xmlCatalogMutex);
3298 xmlFreeRMutex(xmlCatalogMutex);
Daniel Veillarda7374592001-05-10 14:17:55 +00003299}
3300
3301/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003302 * xmlCatalogResolveSystem:
Daniel Veillard06d25242004-02-25 13:01:42 +00003303 * @sysID: the system ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003304 *
3305 * Try to lookup the catalog resource for a system ID
3306 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003307 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003308 * must be freed by the caller.
3309 */
3310xmlChar *
3311xmlCatalogResolveSystem(const xmlChar *sysID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003312 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003313
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003314 if (!xmlCatalogInitialized)
3315 xmlInitializeCatalog();
3316
Daniel Veillard75b96822001-10-11 18:59:45 +00003317 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3318 return(ret);
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003319}
3320
3321/**
3322 * xmlCatalogResolvePublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003323 * @pubID: the public ID string
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003324 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003325 * Try to lookup the catalog reference associated to a public ID
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003326 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003327 * Returns the resource if found or NULL otherwise, the value returned
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003328 * must be freed by the caller.
3329 */
3330xmlChar *
3331xmlCatalogResolvePublic(const xmlChar *pubID) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003332 xmlChar *ret;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003333
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003334 if (!xmlCatalogInitialized)
3335 xmlInitializeCatalog();
3336
Daniel Veillard75b96822001-10-11 18:59:45 +00003337 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3338 return(ret);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003339}
Daniel Veillard344cee72001-08-20 00:08:40 +00003340
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003341/**
Daniel Veillardcda96922001-08-21 10:56:31 +00003342 * xmlCatalogResolve:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003343 * @pubID: the public ID string
3344 * @sysID: the system ID string
Daniel Veillardcda96922001-08-21 10:56:31 +00003345 *
3346 * Do a complete resolution lookup of an External Identifier
3347 *
3348 * Returns the URI of the resource or NULL if not found, it must be freed
3349 * by the caller.
3350 */
3351xmlChar *
3352xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003353 xmlChar *ret;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003354
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003355 if (!xmlCatalogInitialized)
3356 xmlInitializeCatalog();
3357
Daniel Veillard75b96822001-10-11 18:59:45 +00003358 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3359 return(ret);
Daniel Veillardcda96922001-08-21 10:56:31 +00003360}
3361
3362/**
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003363 * xmlCatalogResolveURI:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003364 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003365 *
3366 * Do a complete resolution lookup of an URI
3367 *
3368 * Returns the URI of the resource or NULL if not found, it must be freed
3369 * by the caller.
3370 */
3371xmlChar *
3372xmlCatalogResolveURI(const xmlChar *URI) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003373 xmlChar *ret;
3374
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003375 if (!xmlCatalogInitialized)
3376 xmlInitializeCatalog();
3377
Daniel Veillard75b96822001-10-11 18:59:45 +00003378 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3379 return(ret);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003380}
3381
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003382#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003383/**
Daniel Veillarda7374592001-05-10 14:17:55 +00003384 * xmlCatalogDump:
3385 * @out: the file.
3386 *
Daniel Veillarda8dc2882004-03-29 12:21:26 +00003387 * Dump all the global catalog content to the given file.
Daniel Veillarda7374592001-05-10 14:17:55 +00003388 */
3389void
3390xmlCatalogDump(FILE *out) {
3391 if (out == NULL)
3392 return;
Daniel Veillard344cee72001-08-20 00:08:40 +00003393
Daniel Veillard75b96822001-10-11 18:59:45 +00003394 if (!xmlCatalogInitialized)
3395 xmlInitializeCatalog();
3396
3397 xmlACatalogDump(xmlDefaultCatalog, out);
Daniel Veillard344cee72001-08-20 00:08:40 +00003398}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003399#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard344cee72001-08-20 00:08:40 +00003400
3401/**
3402 * xmlCatalogAdd:
3403 * @type: the type of record to add to the catalog
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003404 * @orig: the system, public or prefix to match
Daniel Veillard344cee72001-08-20 00:08:40 +00003405 * @replace: the replacement value for the match
3406 *
3407 * Add an entry in the catalog, it may overwrite existing but
3408 * different entries.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003409 * If called before any other catalog routine, allows to override the
Daniel Veillard75b96822001-10-11 18:59:45 +00003410 * default shared catalog put in place by xmlInitializeCatalog();
Daniel Veillard344cee72001-08-20 00:08:40 +00003411 *
3412 * Returns 0 if successful, -1 otherwise
3413 */
3414int
3415xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3416 int res = -1;
3417
Daniel Veillard81463942001-10-16 12:34:39 +00003418 if (!xmlCatalogInitialized)
3419 xmlInitializeCatalogData();
3420
3421 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003422 /*
3423 * Specific case where one want to override the default catalog
3424 * put in place by xmlInitializeCatalog();
3425 */
3426 if ((xmlDefaultCatalog == NULL) &&
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003427 (xmlStrEqual(type, BAD_CAST "catalog"))) {
Daniel Veillardcd21dc72001-11-04 20:03:38 +00003428 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
Daniel Veillard75b96822001-10-11 18:59:45 +00003429 xmlCatalogDefaultPrefer);
3430 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003431 orig, NULL, xmlCatalogDefaultPrefer, NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003432
Daniel Veillard81463942001-10-16 12:34:39 +00003433 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003434 return(0);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003435 }
Daniel Veillarde7ead2d2001-08-22 23:44:09 +00003436
Daniel Veillard75b96822001-10-11 18:59:45 +00003437 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
Daniel Veillard81463942001-10-16 12:34:39 +00003438 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard344cee72001-08-20 00:08:40 +00003439 return(res);
3440}
3441
3442/**
3443 * xmlCatalogRemove:
3444 * @value: the value to remove
3445 *
3446 * Remove an entry from the catalog
3447 *
Daniel Veillard82d75332001-10-08 15:01:59 +00003448 * Returns the number of entries removed if successful, -1 otherwise
Daniel Veillard344cee72001-08-20 00:08:40 +00003449 */
3450int
3451xmlCatalogRemove(const xmlChar *value) {
Daniel Veillard75b96822001-10-11 18:59:45 +00003452 int res;
Daniel Veillardcda96922001-08-21 10:56:31 +00003453
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003454 if (!xmlCatalogInitialized)
3455 xmlInitializeCatalog();
3456
Daniel Veillard81463942001-10-16 12:34:39 +00003457 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003458 res = xmlACatalogRemove(xmlDefaultCatalog, value);
Daniel Veillard81463942001-10-16 12:34:39 +00003459 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillardcda96922001-08-21 10:56:31 +00003460 return(res);
Daniel Veillard344cee72001-08-20 00:08:40 +00003461}
3462
3463/**
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003464 * xmlCatalogConvert:
3465 *
3466 * Convert all the SGML catalog entries as XML ones
3467 *
3468 * Returns the number of entries converted if successful, -1 otherwise
3469 */
3470int
3471xmlCatalogConvert(void) {
3472 int res = -1;
3473
3474 if (!xmlCatalogInitialized)
3475 xmlInitializeCatalog();
3476
Daniel Veillard81463942001-10-16 12:34:39 +00003477 xmlRMutexLock(xmlCatalogMutex);
Daniel Veillard75b96822001-10-11 18:59:45 +00003478 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
Daniel Veillard81463942001-10-16 12:34:39 +00003479 xmlRMutexUnlock(xmlCatalogMutex);
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003480 return(res);
3481}
3482
Daniel Veillard75b96822001-10-11 18:59:45 +00003483/************************************************************************
3484 * *
3485 * Public interface manipulating the common preferences *
3486 * *
3487 ************************************************************************/
Daniel Veillard81463942001-10-16 12:34:39 +00003488
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003489/**
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003490 * xmlCatalogGetDefaults:
3491 *
3492 * Used to get the user preference w.r.t. to what catalogs should
3493 * be accepted
3494 *
3495 * Returns the current xmlCatalogAllow value
3496 */
3497xmlCatalogAllow
3498xmlCatalogGetDefaults(void) {
3499 return(xmlCatalogDefaultAllow);
3500}
3501
3502/**
3503 * xmlCatalogSetDefaults:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003504 * @allow: what catalogs should be accepted
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003505 *
3506 * Used to set the user preference w.r.t. to what catalogs should
3507 * be accepted
3508 */
3509void
3510xmlCatalogSetDefaults(xmlCatalogAllow allow) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003511 if (xmlDebugCatalogs) {
3512 switch (allow) {
3513 case XML_CATA_ALLOW_NONE:
3514 xmlGenericError(xmlGenericErrorContext,
3515 "Disabling catalog usage\n");
3516 break;
3517 case XML_CATA_ALLOW_GLOBAL:
3518 xmlGenericError(xmlGenericErrorContext,
3519 "Allowing only global catalogs\n");
3520 break;
3521 case XML_CATA_ALLOW_DOCUMENT:
3522 xmlGenericError(xmlGenericErrorContext,
3523 "Allowing only catalogs from the document\n");
3524 break;
3525 case XML_CATA_ALLOW_ALL:
3526 xmlGenericError(xmlGenericErrorContext,
3527 "Allowing all catalogs\n");
3528 break;
3529 }
3530 }
3531 xmlCatalogDefaultAllow = allow;
3532}
3533
3534/**
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003535 * xmlCatalogSetDefaultPrefer:
3536 * @prefer: the default preference for delegation
3537 *
3538 * Allows to set the preference between public and system for deletion
3539 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003540 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003541 *
3542 * Returns the previous value of the default preference for delegation
3543 */
3544xmlCatalogPrefer
3545xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3546 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3547
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003548 if (prefer == XML_CATA_PREFER_NONE)
3549 return(ret);
3550
3551 if (xmlDebugCatalogs) {
3552 switch (prefer) {
3553 case XML_CATA_PREFER_PUBLIC:
3554 xmlGenericError(xmlGenericErrorContext,
3555 "Setting catalog preference to PUBLIC\n");
3556 break;
3557 case XML_CATA_PREFER_SYSTEM:
3558 xmlGenericError(xmlGenericErrorContext,
3559 "Setting catalog preference to SYSTEM\n");
3560 break;
Daniel Veillardb8bdc252013-09-30 11:12:04 +08003561 default:
3562 return(ret);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003563 }
3564 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003565 xmlCatalogDefaultPrefer = prefer;
3566 return(ret);
3567}
3568
3569/**
Daniel Veillard344cee72001-08-20 00:08:40 +00003570 * xmlCatalogSetDebug:
3571 * @level: the debug level of catalogs required
3572 *
3573 * Used to set the debug level for catalog operation, 0 disable
3574 * debugging, 1 enable it
3575 *
3576 * Returns the previous value of the catalog debugging level
3577 */
3578int
3579xmlCatalogSetDebug(int level) {
3580 int ret = xmlDebugCatalogs;
3581
3582 if (level <= 0)
3583 xmlDebugCatalogs = 0;
3584 else
3585 xmlDebugCatalogs = level;
3586 return(ret);
Daniel Veillarda7374592001-05-10 14:17:55 +00003587}
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003588
Daniel Veillard75b96822001-10-11 18:59:45 +00003589/************************************************************************
3590 * *
3591 * Minimal interfaces used for per-document catalogs by the parser *
3592 * *
3593 ************************************************************************/
3594
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003595/**
3596 * xmlCatalogFreeLocal:
3597 * @catalogs: a document's list of catalogs
3598 *
3599 * Free up the memory associated to the catalog list
3600 */
3601void
3602xmlCatalogFreeLocal(void *catalogs) {
3603 xmlCatalogEntryPtr catal;
3604
Daniel Veillard81463942001-10-16 12:34:39 +00003605 if (!xmlCatalogInitialized)
3606 xmlInitializeCatalog();
3607
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003608 catal = (xmlCatalogEntryPtr) catalogs;
3609 if (catal != NULL)
3610 xmlFreeCatalogEntryList(catal);
3611}
3612
3613
3614/**
3615 * xmlCatalogAddLocal:
3616 * @catalogs: a document's list of catalogs
3617 * @URL: the URL to a new local catalog
3618 *
3619 * Add the new entry to the catalog list
3620 *
3621 * Returns the updated list
3622 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003623void *
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003624xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3625 xmlCatalogEntryPtr catal, add;
3626
3627 if (!xmlCatalogInitialized)
3628 xmlInitializeCatalog();
Daniel Veillard81463942001-10-16 12:34:39 +00003629
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003630 if (URL == NULL)
3631 return(catalogs);
3632
3633 if (xmlDebugCatalogs)
3634 xmlGenericError(xmlGenericErrorContext,
3635 "Adding document catalog %s\n", URL);
3636
Daniel Veillardc853b322001-11-06 15:24:37 +00003637 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
William M. Brackb7b54de2004-10-06 16:38:01 +00003638 xmlCatalogDefaultPrefer, NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003639 if (add == NULL)
3640 return(catalogs);
3641
3642 catal = (xmlCatalogEntryPtr) catalogs;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003643 if (catal == NULL)
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003644 return((void *) add);
3645
3646 while (catal->next != NULL)
3647 catal = catal->next;
3648 catal->next = add;
3649 return(catalogs);
3650}
3651
3652/**
3653 * xmlCatalogLocalResolve:
3654 * @catalogs: a document's list of catalogs
Daniel Veillard5aad8322002-12-11 15:59:44 +00003655 * @pubID: the public ID string
3656 * @sysID: the system ID string
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003657 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003658 * Do a complete resolution lookup of an External Identifier using a
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003659 * document's private catalog list
3660 *
3661 * Returns the URI of the resource or NULL if not found, it must be freed
3662 * by the caller.
3663 */
3664xmlChar *
3665xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3666 const xmlChar *sysID) {
3667 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003668 xmlChar *ret;
3669
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003670 if (!xmlCatalogInitialized)
3671 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003672
Daniel Veillard81463942001-10-16 12:34:39 +00003673 if ((pubID == NULL) && (sysID == NULL))
3674 return(NULL);
3675
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003676 if (xmlDebugCatalogs) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003677 if ((pubID != NULL) && (sysID != NULL)) {
3678 xmlGenericError(xmlGenericErrorContext,
3679 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3680 } else if (pubID != NULL) {
3681 xmlGenericError(xmlGenericErrorContext,
3682 "Local Resolve: pubID %s\n", pubID);
3683 } else {
3684 xmlGenericError(xmlGenericErrorContext,
3685 "Local Resolve: sysID %s\n", sysID);
3686 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +00003687 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00003688
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003689 catal = (xmlCatalogEntryPtr) catalogs;
3690 if (catal == NULL)
3691 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003692 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3693 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3694 return(ret);
3695 return(NULL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003696}
3697
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003698/**
3699 * xmlCatalogLocalResolveURI:
3700 * @catalogs: a document's list of catalogs
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003701 * @URI: the URI
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003702 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003703 * Do a complete resolution lookup of an URI using a
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003704 * document's private catalog list
3705 *
3706 * Returns the URI of the resource or NULL if not found, it must be freed
3707 * by the caller.
3708 */
3709xmlChar *
3710xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3711 xmlCatalogEntryPtr catal;
Daniel Veillard6990bf32001-08-23 21:17:48 +00003712 xmlChar *ret;
3713
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003714 if (!xmlCatalogInitialized)
3715 xmlInitializeCatalog();
Daniel Veillard6990bf32001-08-23 21:17:48 +00003716
Daniel Veillard81463942001-10-16 12:34:39 +00003717 if (URI == NULL)
3718 return(NULL);
3719
Daniel Veillard6990bf32001-08-23 21:17:48 +00003720 if (xmlDebugCatalogs)
3721 xmlGenericError(xmlGenericErrorContext,
3722 "Resolve URI %s\n", URI);
3723
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003724 catal = (xmlCatalogEntryPtr) catalogs;
3725 if (catal == NULL)
3726 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003727 ret = xmlCatalogListXMLResolveURI(catal, URI);
3728 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3729 return(ret);
3730 return(NULL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003731}
3732
Daniel Veillard75b96822001-10-11 18:59:45 +00003733/************************************************************************
3734 * *
3735 * Deprecated interfaces *
3736 * *
3737 ************************************************************************/
3738/**
3739 * xmlCatalogGetSystem:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003740 * @sysID: the system ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003741 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003742 * Try to lookup the catalog reference associated to a system ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003743 * DEPRECATED, use xmlCatalogResolveSystem()
3744 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003745 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003746 */
3747const xmlChar *
3748xmlCatalogGetSystem(const xmlChar *sysID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003749 xmlChar *ret;
3750 static xmlChar result[1000];
3751 static int msg = 0;
3752
3753 if (!xmlCatalogInitialized)
3754 xmlInitializeCatalog();
3755
3756 if (msg == 0) {
3757 xmlGenericError(xmlGenericErrorContext,
3758 "Use of deprecated xmlCatalogGetSystem() call\n");
3759 msg++;
3760 }
3761
3762 if (sysID == NULL)
3763 return(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003764
Daniel Veillardab690c52004-06-14 12:19:09 +00003765 /*
3766 * Check first the XML catalogs
3767 */
3768 if (xmlDefaultCatalog != NULL) {
3769 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3770 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3771 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3772 result[sizeof(result) - 1] = 0;
3773 return(result);
3774 }
3775 }
3776
3777 if (xmlDefaultCatalog != NULL)
3778 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3779 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003780}
3781
3782/**
3783 * xmlCatalogGetPublic:
Daniel Veillard5aad8322002-12-11 15:59:44 +00003784 * @pubID: the public ID string
Daniel Veillard75b96822001-10-11 18:59:45 +00003785 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003786 * Try to lookup the catalog reference associated to a public ID
Daniel Veillard75b96822001-10-11 18:59:45 +00003787 * DEPRECATED, use xmlCatalogResolvePublic()
3788 *
Daniel Veillard06d25242004-02-25 13:01:42 +00003789 * Returns the resource if found or NULL otherwise.
Daniel Veillard75b96822001-10-11 18:59:45 +00003790 */
3791const xmlChar *
3792xmlCatalogGetPublic(const xmlChar *pubID) {
Daniel Veillardab690c52004-06-14 12:19:09 +00003793 xmlChar *ret;
3794 static xmlChar result[1000];
3795 static int msg = 0;
3796
3797 if (!xmlCatalogInitialized)
3798 xmlInitializeCatalog();
3799
3800 if (msg == 0) {
3801 xmlGenericError(xmlGenericErrorContext,
3802 "Use of deprecated xmlCatalogGetPublic() call\n");
3803 msg++;
3804 }
3805
3806 if (pubID == NULL)
3807 return(NULL);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003808
Daniel Veillardab690c52004-06-14 12:19:09 +00003809 /*
3810 * Check first the XML catalogs
3811 */
3812 if (xmlDefaultCatalog != NULL) {
3813 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3814 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3815 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3816 result[sizeof(result) - 1] = 0;
3817 return(result);
3818 }
3819 }
3820
3821 if (xmlDefaultCatalog != NULL)
3822 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3823 return(NULL);
Daniel Veillard75b96822001-10-11 18:59:45 +00003824}
3825
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003826#define bottom_catalog
3827#include "elfgcchack.h"
Daniel Veillarda7374592001-05-10 14:17:55 +00003828#endif /* LIBXML_CATALOG_ENABLED */