VirtualBox

source: vbox/trunk/src/libs/libxml2-2.6.30/catalog.c@ 34034

Last change on this file since 34034 was 6076, checked in by vboxsync, 17 years ago

Merged dmik/s2 branch (r25959:26751) to the trunk.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 96.6 KB
Line 
1/**
2 * catalog.c: set of generic Catalog related routines
3 *
4 * Reference: SGML Open Technical Resolution TR9401:1997.
5 * http://www.jclark.com/sp/catalog.htm
6 *
7 * XML Catalogs Working Draft 06 August 2001
8 * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
9 *
10 * See Copyright for the status of this software.
11 *
12 * [email protected]
13 */
14
15#define IN_LIBXML
16#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
31#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
34#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>
41#include <libxml/threads.h>
42#include <libxml/globals.h>
43
44#define MAX_DELEGATE 50
45#define MAX_CATAL_DEPTH 50
46
47#ifdef _WIN32
48# define PATH_SEAPARATOR ';'
49#else
50# define PATH_SEAPARATOR ':'
51#endif
52
53/**
54 * TODO:
55 *
56 * macro to flag unimplemented blocks
57 * XML_CATALOG_PREFER user env to select between system/public prefered
58 * option. C.f. Richard Tobin <[email protected]>
59 *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
60 *> values "system" and "public". I have made the default be "system" to
61 *> match yours.
62 */
63#define TODO \
64 xmlGenericError(xmlGenericErrorContext, \
65 "Unimplemented block at %s:%d\n", \
66 __FILE__, __LINE__);
67
68#define XML_URN_PUBID "urn:publicid:"
69#define XML_CATAL_BREAK ((xmlChar *) -1)
70#ifndef XML_XML_DEFAULT_CATALOG
71#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog"
72#endif
73#ifndef XML_SGML_DEFAULT_CATALOG
74#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog"
75#endif
76
77#if defined(_WIN32) && defined(_MSC_VER)
78#undef XML_XML_DEFAULT_CATALOG
79static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog";
80#if defined(_WIN32_WCE)
81/* Windows CE don't have a A variant */
82#define GetModuleHandleA GetModuleHandle
83#define GetModuleFileNameA GetModuleFileName
84#else
85void* __stdcall GetModuleHandleA(const char*);
86unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
87#endif
88#endif
89
90static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
91static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
92
93/************************************************************************
94 * *
95 * Types, all private *
96 * *
97 ************************************************************************/
98
99typedef enum {
100 XML_CATA_REMOVED = -1,
101 XML_CATA_NONE = 0,
102 XML_CATA_CATALOG,
103 XML_CATA_BROKEN_CATALOG,
104 XML_CATA_NEXT_CATALOG,
105 XML_CATA_GROUP,
106 XML_CATA_PUBLIC,
107 XML_CATA_SYSTEM,
108 XML_CATA_REWRITE_SYSTEM,
109 XML_CATA_DELEGATE_PUBLIC,
110 XML_CATA_DELEGATE_SYSTEM,
111 XML_CATA_URI,
112 XML_CATA_REWRITE_URI,
113 XML_CATA_DELEGATE_URI,
114 SGML_CATA_SYSTEM,
115 SGML_CATA_PUBLIC,
116 SGML_CATA_ENTITY,
117 SGML_CATA_PENTITY,
118 SGML_CATA_DOCTYPE,
119 SGML_CATA_LINKTYPE,
120 SGML_CATA_NOTATION,
121 SGML_CATA_DELEGATE,
122 SGML_CATA_BASE,
123 SGML_CATA_CATALOG,
124 SGML_CATA_DOCUMENT,
125 SGML_CATA_SGMLDECL
126} xmlCatalogEntryType;
127
128typedef struct _xmlCatalogEntry xmlCatalogEntry;
129typedef xmlCatalogEntry *xmlCatalogEntryPtr;
130struct _xmlCatalogEntry {
131 struct _xmlCatalogEntry *next;
132 struct _xmlCatalogEntry *parent;
133 struct _xmlCatalogEntry *children;
134 xmlCatalogEntryType type;
135 xmlChar *name;
136 xmlChar *value;
137 xmlChar *URL; /* The expanded URL using the base */
138 xmlCatalogPrefer prefer;
139 int dealloc;
140 int depth;
141 struct _xmlCatalogEntry *group;
142};
143
144typedef enum {
145 XML_XML_CATALOG_TYPE = 1,
146 XML_SGML_CATALOG_TYPE
147} xmlCatalogType;
148
149#define XML_MAX_SGML_CATA_DEPTH 10
150struct _xmlCatalog {
151 xmlCatalogType type; /* either XML or SGML */
152
153 /*
154 * SGML Catalogs are stored as a simple hash table of catalog entries
155 * Catalog stack to check against overflows when building the
156 * SGML catalog
157 */
158 char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
159 int catalNr; /* Number of current catal streams */
160 int catalMax; /* Max number of catal streams */
161 xmlHashTablePtr sgml;
162
163 /*
164 * XML Catalogs are stored as a tree of Catalog entries
165 */
166 xmlCatalogPrefer prefer;
167 xmlCatalogEntryPtr xml;
168};
169
170/************************************************************************
171 * *
172 * Global variables *
173 * *
174 ************************************************************************/
175
176/*
177 * Those are preferences
178 */
179static int xmlDebugCatalogs = 0; /* used for debugging */
180static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
181static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
182
183/*
184 * Hash table containing all the trees of XML catalogs parsed by
185 * the application.
186 */
187static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
188
189/*
190 * The default catalog in use by the application
191 */
192static xmlCatalogPtr xmlDefaultCatalog = NULL;
193
194/*
195 * A mutex for modifying the shared global catalog(s)
196 * xmlDefaultCatalog tree.
197 * It also protects xmlCatalogXMLFiles
198 * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
199 */
200static xmlRMutexPtr xmlCatalogMutex = NULL;
201
202/*
203 * Whether the catalog support was initialized.
204 */
205static int xmlCatalogInitialized = 0;
206
207/************************************************************************
208 * *
209 * Catalog error handlers *
210 * *
211 ************************************************************************/
212
213/**
214 * xmlCatalogErrMemory:
215 * @extra: extra informations
216 *
217 * Handle an out of memory condition
218 */
219static void
220xmlCatalogErrMemory(const char *extra)
221{
222 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
223 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
224 extra, NULL, NULL, 0, 0,
225 "Memory allocation failed : %s\n", extra);
226}
227
228/**
229 * xmlCatalogErr:
230 * @catal: the Catalog entry
231 * @node: the context node
232 * @msg: the error message
233 * @extra: extra informations
234 *
235 * Handle a catalog error
236 */
237static void
238xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
239 const char *msg, const xmlChar *str1, const xmlChar *str2,
240 const xmlChar *str3)
241{
242 __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
243 error, XML_ERR_ERROR, NULL, 0,
244 (const char *) str1, (const char *) str2,
245 (const char *) str3, 0, 0,
246 msg, str1, str2, str3);
247}
248
249
250/************************************************************************
251 * *
252 * Allocation and Freeing *
253 * *
254 ************************************************************************/
255
256/**
257 * xmlNewCatalogEntry:
258 * @type: type of entry
259 * @name: name of the entry
260 * @value: value of the entry
261 * @prefer: the PUBLIC vs. SYSTEM current preference value
262 * @group: for members of a group, the group entry
263 *
264 * create a new Catalog entry, this type is shared both by XML and
265 * SGML catalogs, but the acceptable types values differs.
266 *
267 * Returns the xmlCatalogEntryPtr or NULL in case of error
268 */
269static xmlCatalogEntryPtr
270xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
271 const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
272 xmlCatalogEntryPtr group) {
273 xmlCatalogEntryPtr ret;
274 xmlChar *normid = NULL;
275
276 ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
277 if (ret == NULL) {
278 xmlCatalogErrMemory("allocating catalog entry");
279 return(NULL);
280 }
281 ret->next = NULL;
282 ret->parent = NULL;
283 ret->children = NULL;
284 ret->type = type;
285 if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
286 normid = xmlCatalogNormalizePublic(name);
287 if (normid != NULL)
288 name = (*normid != 0 ? normid : NULL);
289 }
290 if (name != NULL)
291 ret->name = xmlStrdup(name);
292 else
293 ret->name = NULL;
294 if (normid != NULL)
295 xmlFree(normid);
296 if (value != NULL)
297 ret->value = xmlStrdup(value);
298 else
299 ret->value = NULL;
300 if (URL == NULL)
301 URL = value;
302 if (URL != NULL)
303 ret->URL = xmlStrdup(URL);
304 else
305 ret->URL = NULL;
306 ret->prefer = prefer;
307 ret->dealloc = 0;
308 ret->depth = 0;
309 ret->group = group;
310 return(ret);
311}
312
313static void
314xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
315
316/**
317 * xmlFreeCatalogEntry:
318 * @ret: a Catalog entry
319 *
320 * Free the memory allocated to a Catalog entry
321 */
322static void
323xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) {
324 if (ret == NULL)
325 return;
326 /*
327 * Entries stored in the file hash must be deallocated
328 * only by the file hash cleaner !
329 */
330 if (ret->dealloc == 1)
331 return;
332
333 if (xmlDebugCatalogs) {
334 if (ret->name != NULL)
335 xmlGenericError(xmlGenericErrorContext,
336 "Free catalog entry %s\n", ret->name);
337 else if (ret->value != NULL)
338 xmlGenericError(xmlGenericErrorContext,
339 "Free catalog entry %s\n", ret->value);
340 else
341 xmlGenericError(xmlGenericErrorContext,
342 "Free catalog entry\n");
343 }
344
345 if (ret->name != NULL)
346 xmlFree(ret->name);
347 if (ret->value != NULL)
348 xmlFree(ret->value);
349 if (ret->URL != NULL)
350 xmlFree(ret->URL);
351 xmlFree(ret);
352}
353
354/**
355 * xmlFreeCatalogEntryList:
356 * @ret: a Catalog entry list
357 *
358 * Free the memory allocated to a full chained list of Catalog entries
359 */
360static void
361xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
362 xmlCatalogEntryPtr next;
363
364 while (ret != NULL) {
365 next = ret->next;
366 xmlFreeCatalogEntry(ret);
367 ret = next;
368 }
369}
370
371/**
372 * xmlFreeCatalogHashEntryList:
373 * @ret: a Catalog entry list
374 *
375 * Free the memory allocated to list of Catalog entries from the
376 * catalog file hash.
377 */
378static void
379xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) {
380 xmlCatalogEntryPtr children, next;
381
382 if (catal == NULL)
383 return;
384
385 children = catal->children;
386 while (children != NULL) {
387 next = children->next;
388 children->dealloc = 0;
389 children->children = NULL;
390 xmlFreeCatalogEntry(children);
391 children = next;
392 }
393 catal->dealloc = 0;
394 xmlFreeCatalogEntry(catal);
395}
396
397/**
398 * xmlCreateNewCatalog:
399 * @type: type of catalog
400 * @prefer: the PUBLIC vs. SYSTEM current preference value
401 *
402 * create a new Catalog, this type is shared both by XML and
403 * SGML catalogs, but the acceptable types values differs.
404 *
405 * Returns the xmlCatalogPtr or NULL in case of error
406 */
407static xmlCatalogPtr
408xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
409 xmlCatalogPtr ret;
410
411 ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
412 if (ret == NULL) {
413 xmlCatalogErrMemory("allocating catalog");
414 return(NULL);
415 }
416 memset(ret, 0, sizeof(xmlCatalog));
417 ret->type = type;
418 ret->catalNr = 0;
419 ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
420 ret->prefer = prefer;
421 if (ret->type == XML_SGML_CATALOG_TYPE)
422 ret->sgml = xmlHashCreate(10);
423 return(ret);
424}
425
426/**
427 * xmlFreeCatalog:
428 * @catal: a Catalog
429 *
430 * Free the memory allocated to a Catalog
431 */
432void
433xmlFreeCatalog(xmlCatalogPtr catal) {
434 if (catal == NULL)
435 return;
436 if (catal->xml != NULL)
437 xmlFreeCatalogEntryList(catal->xml);
438 if (catal->sgml != NULL)
439 xmlHashFree(catal->sgml,
440 (xmlHashDeallocator) xmlFreeCatalogEntry);
441 xmlFree(catal);
442}
443
444/************************************************************************
445 * *
446 * Serializing Catalogs *
447 * *
448 ************************************************************************/
449
450#ifdef LIBXML_OUTPUT_ENABLED
451/**
452 * xmlCatalogDumpEntry:
453 * @entry: the catalog entry
454 * @out: the file.
455 *
456 * Serialize an SGML Catalog entry
457 */
458static void
459xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) {
460 if ((entry == NULL) || (out == NULL))
461 return;
462 switch (entry->type) {
463 case SGML_CATA_ENTITY:
464 fprintf(out, "ENTITY "); break;
465 case SGML_CATA_PENTITY:
466 fprintf(out, "ENTITY %%"); break;
467 case SGML_CATA_DOCTYPE:
468 fprintf(out, "DOCTYPE "); break;
469 case SGML_CATA_LINKTYPE:
470 fprintf(out, "LINKTYPE "); break;
471 case SGML_CATA_NOTATION:
472 fprintf(out, "NOTATION "); break;
473 case SGML_CATA_PUBLIC:
474 fprintf(out, "PUBLIC "); break;
475 case SGML_CATA_SYSTEM:
476 fprintf(out, "SYSTEM "); break;
477 case SGML_CATA_DELEGATE:
478 fprintf(out, "DELEGATE "); break;
479 case SGML_CATA_BASE:
480 fprintf(out, "BASE "); break;
481 case SGML_CATA_CATALOG:
482 fprintf(out, "CATALOG "); break;
483 case SGML_CATA_DOCUMENT:
484 fprintf(out, "DOCUMENT "); break;
485 case SGML_CATA_SGMLDECL:
486 fprintf(out, "SGMLDECL "); break;
487 default:
488 return;
489 }
490 switch (entry->type) {
491 case SGML_CATA_ENTITY:
492 case SGML_CATA_PENTITY:
493 case SGML_CATA_DOCTYPE:
494 case SGML_CATA_LINKTYPE:
495 case SGML_CATA_NOTATION:
496 fprintf(out, "%s", (const char *) entry->name); break;
497 case SGML_CATA_PUBLIC:
498 case SGML_CATA_SYSTEM:
499 case SGML_CATA_SGMLDECL:
500 case SGML_CATA_DOCUMENT:
501 case SGML_CATA_CATALOG:
502 case SGML_CATA_BASE:
503 case SGML_CATA_DELEGATE:
504 fprintf(out, "\"%s\"", entry->name); break;
505 default:
506 break;
507 }
508 switch (entry->type) {
509 case SGML_CATA_ENTITY:
510 case SGML_CATA_PENTITY:
511 case SGML_CATA_DOCTYPE:
512 case SGML_CATA_LINKTYPE:
513 case SGML_CATA_NOTATION:
514 case SGML_CATA_PUBLIC:
515 case SGML_CATA_SYSTEM:
516 case SGML_CATA_DELEGATE:
517 fprintf(out, " \"%s\"", entry->value); break;
518 default:
519 break;
520 }
521 fprintf(out, "\n");
522}
523
524/**
525 * xmlDumpXMLCatalogNode:
526 * @catal: top catalog entry
527 * @catalog: pointer to the xml tree
528 * @doc: the containing document
529 * @ns: the current namespace
530 * @cgroup: group node for group members
531 *
532 * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
533 * for group entries
534 */
535static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
536 xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
537 xmlNodePtr node;
538 xmlCatalogEntryPtr cur;
539 /*
540 * add all the catalog entries
541 */
542 cur = catal;
543 while (cur != NULL) {
544 if (cur->group == cgroup) {
545 switch (cur->type) {
546 case XML_CATA_REMOVED:
547 break;
548 case XML_CATA_BROKEN_CATALOG:
549 case XML_CATA_CATALOG:
550 if (cur == catal) {
551 cur = cur->children;
552 continue;
553 }
554 break;
555 case XML_CATA_NEXT_CATALOG:
556 node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
557 xmlSetProp(node, BAD_CAST "catalog", cur->value);
558 xmlAddChild(catalog, node);
559 break;
560 case XML_CATA_NONE:
561 break;
562 case XML_CATA_GROUP:
563 node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
564 xmlSetProp(node, BAD_CAST "id", cur->name);
565 if (cur->value != NULL) {
566 xmlNsPtr xns;
567 xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
568 if (xns != NULL)
569 xmlSetNsProp(node, xns, BAD_CAST "base",
570 cur->value);
571 }
572 switch (cur->prefer) {
573 case XML_CATA_PREFER_NONE:
574 break;
575 case XML_CATA_PREFER_PUBLIC:
576 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
577 break;
578 case XML_CATA_PREFER_SYSTEM:
579 xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
580 break;
581 }
582 xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
583 xmlAddChild(catalog, node);
584 break;
585 case XML_CATA_PUBLIC:
586 node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
587 xmlSetProp(node, BAD_CAST "publicId", cur->name);
588 xmlSetProp(node, BAD_CAST "uri", cur->value);
589 xmlAddChild(catalog, node);
590 break;
591 case XML_CATA_SYSTEM:
592 node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
593 xmlSetProp(node, BAD_CAST "systemId", cur->name);
594 xmlSetProp(node, BAD_CAST "uri", cur->value);
595 xmlAddChild(catalog, node);
596 break;
597 case XML_CATA_REWRITE_SYSTEM:
598 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
599 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
600 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
601 xmlAddChild(catalog, node);
602 break;
603 case XML_CATA_DELEGATE_PUBLIC:
604 node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
605 xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
606 xmlSetProp(node, BAD_CAST "catalog", cur->value);
607 xmlAddChild(catalog, node);
608 break;
609 case XML_CATA_DELEGATE_SYSTEM:
610 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
611 xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
612 xmlSetProp(node, BAD_CAST "catalog", cur->value);
613 xmlAddChild(catalog, node);
614 break;
615 case XML_CATA_URI:
616 node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
617 xmlSetProp(node, BAD_CAST "name", cur->name);
618 xmlSetProp(node, BAD_CAST "uri", cur->value);
619 xmlAddChild(catalog, node);
620 break;
621 case XML_CATA_REWRITE_URI:
622 node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
623 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
624 xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
625 xmlAddChild(catalog, node);
626 break;
627 case XML_CATA_DELEGATE_URI:
628 node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
629 xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
630 xmlSetProp(node, BAD_CAST "catalog", cur->value);
631 xmlAddChild(catalog, node);
632 break;
633 case SGML_CATA_SYSTEM:
634 case SGML_CATA_PUBLIC:
635 case SGML_CATA_ENTITY:
636 case SGML_CATA_PENTITY:
637 case SGML_CATA_DOCTYPE:
638 case SGML_CATA_LINKTYPE:
639 case SGML_CATA_NOTATION:
640 case SGML_CATA_DELEGATE:
641 case SGML_CATA_BASE:
642 case SGML_CATA_CATALOG:
643 case SGML_CATA_DOCUMENT:
644 case SGML_CATA_SGMLDECL:
645 break;
646 }
647 }
648 cur = cur->next;
649 }
650}
651
652static int
653xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
654 int ret;
655 xmlDocPtr doc;
656 xmlNsPtr ns;
657 xmlDtdPtr dtd;
658 xmlNodePtr catalog;
659 xmlOutputBufferPtr buf;
660
661 /*
662 * Rebuild a catalog
663 */
664 doc = xmlNewDoc(NULL);
665 if (doc == NULL)
666 return(-1);
667 dtd = xmlNewDtd(doc, BAD_CAST "catalog",
668 BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
669BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
670
671 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
672
673 ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
674 if (ns == NULL) {
675 xmlFreeDoc(doc);
676 return(-1);
677 }
678 catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
679 if (catalog == NULL) {
680 xmlFreeNs(ns);
681 xmlFreeDoc(doc);
682 return(-1);
683 }
684 catalog->nsDef = ns;
685 xmlAddChild((xmlNodePtr) doc, catalog);
686
687 xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
688
689 /*
690 * reserialize it
691 */
692 buf = xmlOutputBufferCreateFile(out, NULL);
693 if (buf == NULL) {
694 xmlFreeDoc(doc);
695 return(-1);
696 }
697 ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
698
699 /*
700 * Free it
701 */
702 xmlFreeDoc(doc);
703
704 return(ret);
705}
706#endif /* LIBXML_OUTPUT_ENABLED */
707
708/************************************************************************
709 * *
710 * Converting SGML Catalogs to XML *
711 * *
712 ************************************************************************/
713
714/**
715 * xmlCatalogConvertEntry:
716 * @entry: the entry
717 * @catal: pointer to the catalog being converted
718 *
719 * Convert one entry from the catalog
720 */
721static void
722xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) {
723 if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
724 (catal->xml == NULL))
725 return;
726 switch (entry->type) {
727 case SGML_CATA_ENTITY:
728 entry->type = XML_CATA_PUBLIC;
729 break;
730 case SGML_CATA_PENTITY:
731 entry->type = XML_CATA_PUBLIC;
732 break;
733 case SGML_CATA_DOCTYPE:
734 entry->type = XML_CATA_PUBLIC;
735 break;
736 case SGML_CATA_LINKTYPE:
737 entry->type = XML_CATA_PUBLIC;
738 break;
739 case SGML_CATA_NOTATION:
740 entry->type = XML_CATA_PUBLIC;
741 break;
742 case SGML_CATA_PUBLIC:
743 entry->type = XML_CATA_PUBLIC;
744 break;
745 case SGML_CATA_SYSTEM:
746 entry->type = XML_CATA_SYSTEM;
747 break;
748 case SGML_CATA_DELEGATE:
749 entry->type = XML_CATA_DELEGATE_PUBLIC;
750 break;
751 case SGML_CATA_CATALOG:
752 entry->type = XML_CATA_CATALOG;
753 break;
754 default:
755 xmlHashRemoveEntry(catal->sgml, entry->name,
756 (xmlHashDeallocator) xmlFreeCatalogEntry);
757 return;
758 }
759 /*
760 * Conversion successful, remove from the SGML catalog
761 * and add it to the default XML one
762 */
763 xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
764 entry->parent = catal->xml;
765 entry->next = NULL;
766 if (catal->xml->children == NULL)
767 catal->xml->children = entry;
768 else {
769 xmlCatalogEntryPtr prev;
770
771 prev = catal->xml->children;
772 while (prev->next != NULL)
773 prev = prev->next;
774 prev->next = entry;
775 }
776}
777
778/**
779 * xmlConvertSGMLCatalog:
780 * @catal: the catalog
781 *
782 * Convert all the SGML catalog entries as XML ones
783 *
784 * Returns the number of entries converted if successful, -1 otherwise
785 */
786int
787xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
788
789 if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
790 return(-1);
791
792 if (xmlDebugCatalogs) {
793 xmlGenericError(xmlGenericErrorContext,
794 "Converting SGML catalog to XML\n");
795 }
796 xmlHashScan(catal->sgml,
797 (xmlHashScanner) xmlCatalogConvertEntry,
798 &catal);
799 return(0);
800}
801
802/************************************************************************
803 * *
804 * Helper function *
805 * *
806 ************************************************************************/
807
808/**
809 * xmlCatalogUnWrapURN:
810 * @urn: an "urn:publicid:" to unwrap
811 *
812 * Expand the URN into the equivalent Public Identifier
813 *
814 * Returns the new identifier or NULL, the string must be deallocated
815 * by the caller.
816 */
817static xmlChar *
818xmlCatalogUnWrapURN(const xmlChar *urn) {
819 xmlChar result[2000];
820 unsigned int i = 0;
821
822 if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
823 return(NULL);
824 urn += sizeof(XML_URN_PUBID) - 1;
825
826 while (*urn != 0) {
827 if (i > sizeof(result) - 4)
828 break;
829 if (*urn == '+') {
830 result[i++] = ' ';
831 urn++;
832 } else if (*urn == ':') {
833 result[i++] = '/';
834 result[i++] = '/';
835 urn++;
836 } else if (*urn == ';') {
837 result[i++] = ':';
838 result[i++] = ':';
839 urn++;
840 } else if (*urn == '%') {
841 if ((urn[1] == '2') && (urn[2] == 'B'))
842 result[i++] = '+';
843 else if ((urn[1] == '3') && (urn[2] == 'A'))
844 result[i++] = ':';
845 else if ((urn[1] == '2') && (urn[2] == 'F'))
846 result[i++] = '/';
847 else if ((urn[1] == '3') && (urn[2] == 'B'))
848 result[i++] = ';';
849 else if ((urn[1] == '2') && (urn[2] == '7'))
850 result[i++] = '\'';
851 else if ((urn[1] == '3') && (urn[2] == 'F'))
852 result[i++] = '?';
853 else if ((urn[1] == '2') && (urn[2] == '3'))
854 result[i++] = '#';
855 else if ((urn[1] == '2') && (urn[2] == '5'))
856 result[i++] = '%';
857 else {
858 result[i++] = *urn;
859 urn++;
860 continue;
861 }
862 urn += 3;
863 } else {
864 result[i++] = *urn;
865 urn++;
866 }
867 }
868 result[i] = 0;
869
870 return(xmlStrdup(result));
871}
872
873/**
874 * xmlParseCatalogFile:
875 * @filename: the filename
876 *
877 * parse an XML file and build a tree. It's like xmlParseFile()
878 * except it bypass all catalog lookups.
879 *
880 * Returns the resulting document tree or NULL in case of error
881 */
882
883xmlDocPtr
884xmlParseCatalogFile(const char *filename) {
885 xmlDocPtr ret;
886 xmlParserCtxtPtr ctxt;
887 char *directory = NULL;
888 xmlParserInputPtr inputStream;
889 xmlParserInputBufferPtr buf;
890
891 ctxt = xmlNewParserCtxt();
892 if (ctxt == NULL) {
893#ifdef LIBXML_SAX1_ENABLED
894 if (xmlDefaultSAXHandler.error != NULL) {
895 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
896 }
897#endif
898 return(NULL);
899 }
900
901 buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
902 if (buf == NULL) {
903 xmlFreeParserCtxt(ctxt);
904 return(NULL);
905 }
906
907 inputStream = xmlNewInputStream(ctxt);
908 if (inputStream == NULL) {
909 xmlFreeParserCtxt(ctxt);
910 return(NULL);
911 }
912
913 inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
914 inputStream->buf = buf;
915 inputStream->base = inputStream->buf->buffer->content;
916 inputStream->cur = inputStream->buf->buffer->content;
917 inputStream->end =
918 &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
919
920 inputPush(ctxt, inputStream);
921 if ((ctxt->directory == NULL) && (directory == NULL))
922 directory = xmlParserGetDirectory(filename);
923 if ((ctxt->directory == NULL) && (directory != NULL))
924 ctxt->directory = directory;
925 ctxt->valid = 0;
926 ctxt->validate = 0;
927 ctxt->loadsubset = 0;
928 ctxt->pedantic = 0;
929 ctxt->dictNames = 1;
930
931 xmlParseDocument(ctxt);
932
933 if (ctxt->wellFormed)
934 ret = ctxt->myDoc;
935 else {
936 ret = NULL;
937 xmlFreeDoc(ctxt->myDoc);
938 ctxt->myDoc = NULL;
939 }
940 xmlFreeParserCtxt(ctxt);
941
942 return(ret);
943}
944
945/**
946 * xmlLoadFileContent:
947 * @filename: a file path
948 *
949 * Load a file content into memory.
950 *
951 * Returns a pointer to the 0 terminated string or NULL in case of error
952 */
953static xmlChar *
954xmlLoadFileContent(const char *filename)
955{
956#ifdef HAVE_STAT
957 int fd;
958#else
959 FILE *fd;
960#endif
961 int len;
962 long size;
963
964#ifdef HAVE_STAT
965 struct stat info;
966#endif
967 xmlChar *content;
968
969 if (filename == NULL)
970 return (NULL);
971
972#ifdef HAVE_STAT
973 if (stat(filename, &info) < 0)
974 return (NULL);
975#endif
976
977#ifdef HAVE_STAT
978 if ((fd = open(filename, O_RDONLY)) < 0)
979#else
980 if ((fd = fopen(filename, "rb")) == NULL)
981#endif
982 {
983 return (NULL);
984 }
985#ifdef HAVE_STAT
986 size = info.st_size;
987#else
988 if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
989 fclose(fd);
990 return (NULL);
991 }
992#endif
993 content = xmlMallocAtomic(size + 10);
994 if (content == NULL) {
995 xmlCatalogErrMemory("allocating catalog data");
996 return (NULL);
997 }
998#ifdef HAVE_STAT
999 len = read(fd, content, size);
1000#else
1001 len = fread(content, 1, size, fd);
1002#endif
1003 if (len < 0) {
1004 xmlFree(content);
1005 return (NULL);
1006 }
1007#ifdef HAVE_STAT
1008 close(fd);
1009#else
1010 fclose(fd);
1011#endif
1012 content[len] = 0;
1013
1014 return(content);
1015}
1016
1017/**
1018 * xmlCatalogNormalizePublic:
1019 * @pubID: the public ID string
1020 *
1021 * Normalizes the Public Identifier
1022 *
1023 * Implements 6.2. Public Identifier Normalization
1024 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1025 *
1026 * Returns the new string or NULL, the string must be deallocated
1027 * by the caller.
1028 */
1029static xmlChar *
1030xmlCatalogNormalizePublic(const xmlChar *pubID)
1031{
1032 int ok = 1;
1033 int white;
1034 const xmlChar *p;
1035 xmlChar *ret;
1036 xmlChar *q;
1037
1038 if (pubID == NULL)
1039 return(NULL);
1040
1041 white = 1;
1042 for (p = pubID;*p != 0 && ok;p++) {
1043 if (!xmlIsBlank_ch(*p))
1044 white = 0;
1045 else if (*p == 0x20 && !white)
1046 white = 1;
1047 else
1048 ok = 0;
1049 }
1050 if (ok && !white) /* is normalized */
1051 return(NULL);
1052
1053 ret = xmlStrdup(pubID);
1054 q = ret;
1055 white = 0;
1056 for (p = pubID;*p != 0;p++) {
1057 if (xmlIsBlank_ch(*p)) {
1058 if (q != ret)
1059 white = 1;
1060 } else {
1061 if (white) {
1062 *(q++) = 0x20;
1063 white = 0;
1064 }
1065 *(q++) = *p;
1066 }
1067 }
1068 *q = 0;
1069 return(ret);
1070}
1071
1072/************************************************************************
1073 * *
1074 * The XML Catalog parser *
1075 * *
1076 ************************************************************************/
1077
1078static xmlCatalogEntryPtr
1079xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
1080static void
1081xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1082 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
1083static xmlChar *
1084xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1085 const xmlChar *sysID);
1086static xmlChar *
1087xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
1088
1089
1090/**
1091 * xmlGetXMLCatalogEntryType:
1092 * @name: the name
1093 *
1094 * lookup the internal type associated to an XML catalog entry name
1095 *
1096 * Returns the type associated with that name
1097 */
1098static xmlCatalogEntryType
1099xmlGetXMLCatalogEntryType(const xmlChar *name) {
1100 xmlCatalogEntryType type = XML_CATA_NONE;
1101 if (xmlStrEqual(name, (const xmlChar *) "system"))
1102 type = XML_CATA_SYSTEM;
1103 else if (xmlStrEqual(name, (const xmlChar *) "public"))
1104 type = XML_CATA_PUBLIC;
1105 else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
1106 type = XML_CATA_REWRITE_SYSTEM;
1107 else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
1108 type = XML_CATA_DELEGATE_PUBLIC;
1109 else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
1110 type = XML_CATA_DELEGATE_SYSTEM;
1111 else if (xmlStrEqual(name, (const xmlChar *) "uri"))
1112 type = XML_CATA_URI;
1113 else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
1114 type = XML_CATA_REWRITE_URI;
1115 else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
1116 type = XML_CATA_DELEGATE_URI;
1117 else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
1118 type = XML_CATA_NEXT_CATALOG;
1119 else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
1120 type = XML_CATA_CATALOG;
1121 return(type);
1122}
1123
1124/**
1125 * xmlParseXMLCatalogOneNode:
1126 * @cur: the XML node
1127 * @type: the type of Catalog entry
1128 * @name: the name of the node
1129 * @attrName: the attribute holding the value
1130 * @uriAttrName: the attribute holding the URI-Reference
1131 * @prefer: the PUBLIC vs. SYSTEM current preference value
1132 * @cgroup: the group which includes this node
1133 *
1134 * Finishes the examination of an XML tree node of a catalog and build
1135 * a Catalog entry from it.
1136 *
1137 * Returns the new Catalog entry node or NULL in case of error.
1138 */
1139static xmlCatalogEntryPtr
1140xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
1141 const xmlChar *name, const xmlChar *attrName,
1142 const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
1143 xmlCatalogEntryPtr cgroup) {
1144 int ok = 1;
1145 xmlChar *uriValue;
1146 xmlChar *nameValue = NULL;
1147 xmlChar *base = NULL;
1148 xmlChar *URL = NULL;
1149 xmlCatalogEntryPtr ret = NULL;
1150
1151 if (attrName != NULL) {
1152 nameValue = xmlGetProp(cur, attrName);
1153 if (nameValue == NULL) {
1154 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1155 "%s entry lacks '%s'\n", name, attrName, NULL);
1156 ok = 0;
1157 }
1158 }
1159 uriValue = xmlGetProp(cur, uriAttrName);
1160 if (uriValue == NULL) {
1161 xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
1162 "%s entry lacks '%s'\n", name, uriAttrName, NULL);
1163 ok = 0;
1164 }
1165 if (!ok) {
1166 if (nameValue != NULL)
1167 xmlFree(nameValue);
1168 if (uriValue != NULL)
1169 xmlFree(uriValue);
1170 return(NULL);
1171 }
1172
1173 base = xmlNodeGetBase(cur->doc, cur);
1174 URL = xmlBuildURI(uriValue, base);
1175 if (URL != NULL) {
1176 if (xmlDebugCatalogs > 1) {
1177 if (nameValue != NULL)
1178 xmlGenericError(xmlGenericErrorContext,
1179 "Found %s: '%s' '%s'\n", name, nameValue, URL);
1180 else
1181 xmlGenericError(xmlGenericErrorContext,
1182 "Found %s: '%s'\n", name, URL);
1183 }
1184 ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
1185 } else {
1186 xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
1187 "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
1188 }
1189 if (nameValue != NULL)
1190 xmlFree(nameValue);
1191 if (uriValue != NULL)
1192 xmlFree(uriValue);
1193 if (base != NULL)
1194 xmlFree(base);
1195 if (URL != NULL)
1196 xmlFree(URL);
1197 return(ret);
1198}
1199
1200/**
1201 * xmlParseXMLCatalogNode:
1202 * @cur: the XML node
1203 * @prefer: the PUBLIC vs. SYSTEM current preference value
1204 * @parent: the parent Catalog entry
1205 * @cgroup: the group which includes this node
1206 *
1207 * Examines an XML tree node of a catalog and build
1208 * a Catalog entry from it adding it to its parent. The examination can
1209 * be recursive.
1210 */
1211static void
1212xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
1213 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
1214{
1215 xmlChar *base = NULL;
1216 xmlCatalogEntryPtr entry = NULL;
1217
1218 if (cur == NULL)
1219 return;
1220 if (xmlStrEqual(cur->name, BAD_CAST "group")) {
1221 xmlChar *prop;
1222 xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
1223
1224 prop = xmlGetProp(cur, BAD_CAST "prefer");
1225 if (prop != NULL) {
1226 if (xmlStrEqual(prop, BAD_CAST "system")) {
1227 prefer = XML_CATA_PREFER_SYSTEM;
1228 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1229 prefer = XML_CATA_PREFER_PUBLIC;
1230 } else {
1231 xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
1232 "Invalid value for prefer: '%s'\n",
1233 prop, NULL, NULL);
1234 }
1235 xmlFree(prop);
1236 pref = prefer;
1237 }
1238 prop = xmlGetProp(cur, BAD_CAST "id");
1239 base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1240 entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
1241 xmlFree(prop);
1242 } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
1243 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
1244 BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
1245 } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
1246 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
1247 BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
1248 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
1249 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
1250 BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
1251 BAD_CAST "rewritePrefix", prefer, cgroup);
1252 } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
1253 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
1254 BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
1255 BAD_CAST "catalog", prefer, cgroup);
1256 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
1257 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
1258 BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
1259 BAD_CAST "catalog", prefer, cgroup);
1260 } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
1261 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
1262 BAD_CAST "uri", BAD_CAST "name",
1263 BAD_CAST "uri", prefer, cgroup);
1264 } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
1265 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
1266 BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
1267 BAD_CAST "rewritePrefix", prefer, cgroup);
1268 } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
1269 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
1270 BAD_CAST "delegateURI", BAD_CAST "uriStartString",
1271 BAD_CAST "catalog", prefer, cgroup);
1272 } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
1273 entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
1274 BAD_CAST "nextCatalog", NULL,
1275 BAD_CAST "catalog", prefer, cgroup);
1276 }
1277 if (entry != NULL) {
1278 if (parent != NULL) {
1279 entry->parent = parent;
1280 if (parent->children == NULL)
1281 parent->children = entry;
1282 else {
1283 xmlCatalogEntryPtr prev;
1284
1285 prev = parent->children;
1286 while (prev->next != NULL)
1287 prev = prev->next;
1288 prev->next = entry;
1289 }
1290 }
1291 if (entry->type == XML_CATA_GROUP) {
1292 /*
1293 * Recurse to propagate prefer to the subtree
1294 * (xml:base handling is automated)
1295 */
1296 xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
1297 }
1298 }
1299 if (base != NULL)
1300 xmlFree(base);
1301}
1302
1303/**
1304 * xmlParseXMLCatalogNodeList:
1305 * @cur: the XML node list of siblings
1306 * @prefer: the PUBLIC vs. SYSTEM current preference value
1307 * @parent: the parent Catalog entry
1308 * @cgroup: the group which includes this list
1309 *
1310 * Examines a list of XML sibling nodes of a catalog and build
1311 * a list of Catalog entry from it adding it to the parent.
1312 * The examination will recurse to examine node subtrees.
1313 */
1314static void
1315xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
1316 xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
1317 while (cur != NULL) {
1318 if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
1319 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1320 xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
1321 }
1322 cur = cur->next;
1323 }
1324 /* TODO: sort the list according to REWRITE lengths and prefer value */
1325}
1326
1327/**
1328 * xmlParseXMLCatalogFile:
1329 * @prefer: the PUBLIC vs. SYSTEM current preference value
1330 * @filename: the filename for the catalog
1331 *
1332 * Parses the catalog file to extract the XML tree and then analyze the
1333 * tree to build a list of Catalog entries corresponding to this catalog
1334 *
1335 * Returns the resulting Catalog entries list
1336 */
1337static xmlCatalogEntryPtr
1338xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
1339 xmlDocPtr doc;
1340 xmlNodePtr cur;
1341 xmlChar *prop;
1342 xmlCatalogEntryPtr parent = NULL;
1343
1344 if (filename == NULL)
1345 return(NULL);
1346
1347 doc = xmlParseCatalogFile((const char *) filename);
1348 if (doc == NULL) {
1349 if (xmlDebugCatalogs)
1350 xmlGenericError(xmlGenericErrorContext,
1351 "Failed to parse catalog %s\n", filename);
1352 return(NULL);
1353 }
1354
1355 if (xmlDebugCatalogs)
1356 xmlGenericError(xmlGenericErrorContext,
1357 "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
1358
1359 cur = xmlDocGetRootElement(doc);
1360 if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
1361 (cur->ns != NULL) && (cur->ns->href != NULL) &&
1362 (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
1363
1364 parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
1365 (const xmlChar *)filename, NULL, prefer, NULL);
1366 if (parent == NULL) {
1367 xmlFreeDoc(doc);
1368 return(NULL);
1369 }
1370
1371 prop = xmlGetProp(cur, BAD_CAST "prefer");
1372 if (prop != NULL) {
1373 if (xmlStrEqual(prop, BAD_CAST "system")) {
1374 prefer = XML_CATA_PREFER_SYSTEM;
1375 } else if (xmlStrEqual(prop, BAD_CAST "public")) {
1376 prefer = XML_CATA_PREFER_PUBLIC;
1377 } else {
1378 xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
1379 "Invalid value for prefer: '%s'\n",
1380 prop, NULL, NULL);
1381 }
1382 xmlFree(prop);
1383 }
1384 cur = cur->children;
1385 xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
1386 } else {
1387 xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
1388 "File %s is not an XML Catalog\n",
1389 filename, NULL, NULL);
1390 xmlFreeDoc(doc);
1391 return(NULL);
1392 }
1393 xmlFreeDoc(doc);
1394 return(parent);
1395}
1396
1397/**
1398 * xmlFetchXMLCatalogFile:
1399 * @catal: an existing but incomplete catalog entry
1400 *
1401 * Fetch and parse the subcatalog referenced by an entry
1402 *
1403 * Returns 0 in case of success, -1 otherwise
1404 */
1405static int
1406xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
1407 xmlCatalogEntryPtr doc;
1408
1409 if (catal == NULL)
1410 return(-1);
1411 if (catal->URL == NULL)
1412 return(-1);
1413 if (catal->children != NULL)
1414 return(-1);
1415
1416 /*
1417 * lock the whole catalog for modification
1418 */
1419 xmlRMutexLock(xmlCatalogMutex);
1420 if (catal->children != NULL) {
1421 /* Okay someone else did it in the meantime */
1422 xmlRMutexUnlock(xmlCatalogMutex);
1423 return(0);
1424 }
1425
1426 if (xmlCatalogXMLFiles != NULL) {
1427 doc = (xmlCatalogEntryPtr)
1428 xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1429 if (doc != NULL) {
1430 if (xmlDebugCatalogs)
1431 xmlGenericError(xmlGenericErrorContext,
1432 "Found %s in file hash\n", catal->URL);
1433
1434 if (catal->type == XML_CATA_CATALOG)
1435 catal->children = doc->children;
1436 else
1437 catal->children = doc;
1438 catal->dealloc = 0;
1439 xmlRMutexUnlock(xmlCatalogMutex);
1440 return(0);
1441 }
1442 if (xmlDebugCatalogs)
1443 xmlGenericError(xmlGenericErrorContext,
1444 "%s not found in file hash\n", catal->URL);
1445 }
1446
1447 /*
1448 * Fetch and parse. Note that xmlParseXMLCatalogFile does not
1449 * use the existing catalog, there is no recursion allowed at
1450 * that level.
1451 */
1452 doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL);
1453 if (doc == NULL) {
1454 catal->type = XML_CATA_BROKEN_CATALOG;
1455 xmlRMutexUnlock(xmlCatalogMutex);
1456 return(-1);
1457 }
1458
1459 if (catal->type == XML_CATA_CATALOG)
1460 catal->children = doc->children;
1461 else
1462 catal->children = doc;
1463
1464 doc->dealloc = 1;
1465
1466 if (xmlCatalogXMLFiles == NULL)
1467 xmlCatalogXMLFiles = xmlHashCreate(10);
1468 if (xmlCatalogXMLFiles != NULL) {
1469 if (xmlDebugCatalogs)
1470 xmlGenericError(xmlGenericErrorContext,
1471 "%s added to file hash\n", catal->URL);
1472 xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc);
1473 }
1474 xmlRMutexUnlock(xmlCatalogMutex);
1475 return(0);
1476}
1477
1478/************************************************************************
1479 * *
1480 * XML Catalog handling *
1481 * *
1482 ************************************************************************/
1483
1484/**
1485 * xmlAddXMLCatalog:
1486 * @catal: top of an XML catalog
1487 * @type: the type of record to add to the catalog
1488 * @orig: the system, public or prefix to match (or NULL)
1489 * @replace: the replacement value for the match
1490 *
1491 * Add an entry in the XML catalog, it may overwrite existing but
1492 * different entries.
1493 *
1494 * Returns 0 if successful, -1 otherwise
1495 */
1496static int
1497xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type,
1498 const xmlChar *orig, const xmlChar *replace) {
1499 xmlCatalogEntryPtr cur;
1500 xmlCatalogEntryType typ;
1501 int doregister = 0;
1502
1503 if ((catal == NULL) ||
1504 ((catal->type != XML_CATA_CATALOG) &&
1505 (catal->type != XML_CATA_BROKEN_CATALOG)))
1506 return(-1);
1507 if (catal->children == NULL) {
1508 xmlFetchXMLCatalogFile(catal);
1509 }
1510 if (catal->children == NULL)
1511 doregister = 1;
1512
1513 typ = xmlGetXMLCatalogEntryType(type);
1514 if (typ == XML_CATA_NONE) {
1515 if (xmlDebugCatalogs)
1516 xmlGenericError(xmlGenericErrorContext,
1517 "Failed to add unknown element %s to catalog\n", type);
1518 return(-1);
1519 }
1520
1521 cur = catal->children;
1522 /*
1523 * Might be a simple "update in place"
1524 */
1525 if (cur != NULL) {
1526 while (cur != NULL) {
1527 if ((orig != NULL) && (cur->type == typ) &&
1528 (xmlStrEqual(orig, cur->name))) {
1529 if (xmlDebugCatalogs)
1530 xmlGenericError(xmlGenericErrorContext,
1531 "Updating element %s to catalog\n", type);
1532 if (cur->value != NULL)
1533 xmlFree(cur->value);
1534 if (cur->URL != NULL)
1535 xmlFree(cur->URL);
1536 cur->value = xmlStrdup(replace);
1537 cur->URL = xmlStrdup(replace);
1538 return(0);
1539 }
1540 if (cur->next == NULL)
1541 break;
1542 cur = cur->next;
1543 }
1544 }
1545 if (xmlDebugCatalogs)
1546 xmlGenericError(xmlGenericErrorContext,
1547 "Adding element %s to catalog\n", type);
1548 if (cur == NULL)
1549 catal->children = xmlNewCatalogEntry(typ, orig, replace,
1550 NULL, catal->prefer, NULL);
1551 else
1552 cur->next = xmlNewCatalogEntry(typ, orig, replace,
1553 NULL, catal->prefer, NULL);
1554 if (doregister) {
1555 catal->type = XML_CATA_CATALOG;
1556 cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL);
1557 if (cur != NULL)
1558 cur->children = catal->children;
1559 }
1560
1561 return(0);
1562}
1563
1564/**
1565 * xmlDelXMLCatalog:
1566 * @catal: top of an XML catalog
1567 * @value: the value to remove from the catalog
1568 *
1569 * Remove entries in the XML catalog where the value or the URI
1570 * is equal to @value
1571 *
1572 * Returns the number of entries removed if successful, -1 otherwise
1573 */
1574static int
1575xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) {
1576 xmlCatalogEntryPtr cur;
1577 int ret = 0;
1578
1579 if ((catal == NULL) ||
1580 ((catal->type != XML_CATA_CATALOG) &&
1581 (catal->type != XML_CATA_BROKEN_CATALOG)))
1582 return(-1);
1583 if (value == NULL)
1584 return(-1);
1585 if (catal->children == NULL) {
1586 xmlFetchXMLCatalogFile(catal);
1587 }
1588
1589 /*
1590 * Scan the children
1591 */
1592 cur = catal->children;
1593 while (cur != NULL) {
1594 if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
1595 (xmlStrEqual(value, cur->value))) {
1596 if (xmlDebugCatalogs) {
1597 if (cur->name != NULL)
1598 xmlGenericError(xmlGenericErrorContext,
1599 "Removing element %s from catalog\n", cur->name);
1600 else
1601 xmlGenericError(xmlGenericErrorContext,
1602 "Removing element %s from catalog\n", cur->value);
1603 }
1604 cur->type = XML_CATA_REMOVED;
1605 }
1606 cur = cur->next;
1607 }
1608 return(ret);
1609}
1610
1611/**
1612 * xmlCatalogXMLResolve:
1613 * @catal: a catalog list
1614 * @pubID: the public ID string
1615 * @sysID: the system ID string
1616 *
1617 * Do a complete resolution lookup of an External Identifier for a
1618 * list of catalog entries.
1619 *
1620 * Implements (or tries to) 7.1. External Identifier Resolution
1621 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1622 *
1623 * Returns the URI of the resource or NULL if not found
1624 */
1625static xmlChar *
1626xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
1627 const xmlChar *sysID) {
1628 xmlChar *ret = NULL;
1629 xmlCatalogEntryPtr cur;
1630 int haveDelegate = 0;
1631 int haveNext = 0;
1632
1633 /*
1634 * protection against loops
1635 */
1636 if (catal->depth > MAX_CATAL_DEPTH) {
1637 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1638 "Detected recursion in catalog %s\n",
1639 catal->name, NULL, NULL);
1640 return(NULL);
1641 }
1642 catal->depth++;
1643
1644 /*
1645 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1646 */
1647 if (sysID != NULL) {
1648 xmlCatalogEntryPtr rewrite = NULL;
1649 int lenrewrite = 0, len;
1650 cur = catal;
1651 haveDelegate = 0;
1652 while (cur != NULL) {
1653 switch (cur->type) {
1654 case XML_CATA_SYSTEM:
1655 if (xmlStrEqual(sysID, cur->name)) {
1656 if (xmlDebugCatalogs)
1657 xmlGenericError(xmlGenericErrorContext,
1658 "Found system match %s, using %s\n",
1659 cur->name, cur->URL);
1660 catal->depth--;
1661 return(xmlStrdup(cur->URL));
1662 }
1663 break;
1664 case XML_CATA_REWRITE_SYSTEM:
1665 len = xmlStrlen(cur->name);
1666 if ((len > lenrewrite) &&
1667 (!xmlStrncmp(sysID, cur->name, len))) {
1668 lenrewrite = len;
1669 rewrite = cur;
1670 }
1671 break;
1672 case XML_CATA_DELEGATE_SYSTEM:
1673 if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))
1674 haveDelegate++;
1675 break;
1676 case XML_CATA_NEXT_CATALOG:
1677 haveNext++;
1678 break;
1679 default:
1680 break;
1681 }
1682 cur = cur->next;
1683 }
1684 if (rewrite != NULL) {
1685 if (xmlDebugCatalogs)
1686 xmlGenericError(xmlGenericErrorContext,
1687 "Using rewriting rule %s\n", rewrite->name);
1688 ret = xmlStrdup(rewrite->URL);
1689 if (ret != NULL)
1690 ret = xmlStrcat(ret, &sysID[lenrewrite]);
1691 catal->depth--;
1692 return(ret);
1693 }
1694 if (haveDelegate) {
1695 const xmlChar *delegates[MAX_DELEGATE];
1696 int nbList = 0, i;
1697
1698 /*
1699 * Assume the entries have been sorted by decreasing substring
1700 * matches when the list was produced.
1701 */
1702 cur = catal;
1703 while (cur != NULL) {
1704 if ((cur->type == XML_CATA_DELEGATE_SYSTEM) &&
1705 (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
1706 for (i = 0;i < nbList;i++)
1707 if (xmlStrEqual(cur->URL, delegates[i]))
1708 break;
1709 if (i < nbList) {
1710 cur = cur->next;
1711 continue;
1712 }
1713 if (nbList < MAX_DELEGATE)
1714 delegates[nbList++] = cur->URL;
1715
1716 if (cur->children == NULL) {
1717 xmlFetchXMLCatalogFile(cur);
1718 }
1719 if (cur->children != NULL) {
1720 if (xmlDebugCatalogs)
1721 xmlGenericError(xmlGenericErrorContext,
1722 "Trying system delegate %s\n", cur->URL);
1723 ret = xmlCatalogListXMLResolve(
1724 cur->children, NULL, sysID);
1725 if (ret != NULL) {
1726 catal->depth--;
1727 return(ret);
1728 }
1729 }
1730 }
1731 cur = cur->next;
1732 }
1733 /*
1734 * Apply the cut algorithm explained in 4/
1735 */
1736 catal->depth--;
1737 return(XML_CATAL_BREAK);
1738 }
1739 }
1740 /*
1741 * Then tries 5/ 6/ if a public ID is provided
1742 */
1743 if (pubID != NULL) {
1744 cur = catal;
1745 haveDelegate = 0;
1746 while (cur != NULL) {
1747 switch (cur->type) {
1748 case XML_CATA_PUBLIC:
1749 if (xmlStrEqual(pubID, cur->name)) {
1750 if (xmlDebugCatalogs)
1751 xmlGenericError(xmlGenericErrorContext,
1752 "Found public match %s\n", cur->name);
1753 catal->depth--;
1754 return(xmlStrdup(cur->URL));
1755 }
1756 break;
1757 case XML_CATA_DELEGATE_PUBLIC:
1758 if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
1759 (cur->prefer == XML_CATA_PREFER_PUBLIC))
1760 haveDelegate++;
1761 break;
1762 case XML_CATA_NEXT_CATALOG:
1763 if (sysID == NULL)
1764 haveNext++;
1765 break;
1766 default:
1767 break;
1768 }
1769 cur = cur->next;
1770 }
1771 if (haveDelegate) {
1772 const xmlChar *delegates[MAX_DELEGATE];
1773 int nbList = 0, i;
1774
1775 /*
1776 * Assume the entries have been sorted by decreasing substring
1777 * matches when the list was produced.
1778 */
1779 cur = catal;
1780 while (cur != NULL) {
1781 if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
1782 (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
1783 (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
1784
1785 for (i = 0;i < nbList;i++)
1786 if (xmlStrEqual(cur->URL, delegates[i]))
1787 break;
1788 if (i < nbList) {
1789 cur = cur->next;
1790 continue;
1791 }
1792 if (nbList < MAX_DELEGATE)
1793 delegates[nbList++] = cur->URL;
1794
1795 if (cur->children == NULL) {
1796 xmlFetchXMLCatalogFile(cur);
1797 }
1798 if (cur->children != NULL) {
1799 if (xmlDebugCatalogs)
1800 xmlGenericError(xmlGenericErrorContext,
1801 "Trying public delegate %s\n", cur->URL);
1802 ret = xmlCatalogListXMLResolve(
1803 cur->children, pubID, NULL);
1804 if (ret != NULL) {
1805 catal->depth--;
1806 return(ret);
1807 }
1808 }
1809 }
1810 cur = cur->next;
1811 }
1812 /*
1813 * Apply the cut algorithm explained in 4/
1814 */
1815 catal->depth--;
1816 return(XML_CATAL_BREAK);
1817 }
1818 }
1819 if (haveNext) {
1820 cur = catal;
1821 while (cur != NULL) {
1822 if (cur->type == XML_CATA_NEXT_CATALOG) {
1823 if (cur->children == NULL) {
1824 xmlFetchXMLCatalogFile(cur);
1825 }
1826 if (cur->children != NULL) {
1827 ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID);
1828 if (ret != NULL) {
1829 catal->depth--;
1830 return(ret);
1831 } else if (catal->depth > MAX_CATAL_DEPTH) {
1832 return(NULL);
1833 }
1834 }
1835 }
1836 cur = cur->next;
1837 }
1838 }
1839
1840 catal->depth--;
1841 return(NULL);
1842}
1843
1844/**
1845 * xmlCatalogXMLResolveURI:
1846 * @catal: a catalog list
1847 * @URI: the URI
1848 * @sysID: the system ID string
1849 *
1850 * Do a complete resolution lookup of an External Identifier for a
1851 * list of catalog entries.
1852 *
1853 * Implements (or tries to) 7.2.2. URI Resolution
1854 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1855 *
1856 * Returns the URI of the resource or NULL if not found
1857 */
1858static xmlChar *
1859xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
1860 xmlChar *ret = NULL;
1861 xmlCatalogEntryPtr cur;
1862 int haveDelegate = 0;
1863 int haveNext = 0;
1864 xmlCatalogEntryPtr rewrite = NULL;
1865 int lenrewrite = 0, len;
1866
1867 if (catal == NULL)
1868 return(NULL);
1869
1870 if (URI == NULL)
1871 return(NULL);
1872
1873 if (catal->depth > MAX_CATAL_DEPTH) {
1874 xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION,
1875 "Detected recursion in catalog %s\n",
1876 catal->name, NULL, NULL);
1877 return(NULL);
1878 }
1879
1880 /*
1881 * First tries steps 2/ 3/ 4/ if a system ID is provided.
1882 */
1883 cur = catal;
1884 haveDelegate = 0;
1885 while (cur != NULL) {
1886 switch (cur->type) {
1887 case XML_CATA_URI:
1888 if (xmlStrEqual(URI, cur->name)) {
1889 if (xmlDebugCatalogs)
1890 xmlGenericError(xmlGenericErrorContext,
1891 "Found URI match %s\n", cur->name);
1892 return(xmlStrdup(cur->URL));
1893 }
1894 break;
1895 case XML_CATA_REWRITE_URI:
1896 len = xmlStrlen(cur->name);
1897 if ((len > lenrewrite) &&
1898 (!xmlStrncmp(URI, cur->name, len))) {
1899 lenrewrite = len;
1900 rewrite = cur;
1901 }
1902 break;
1903 case XML_CATA_DELEGATE_URI:
1904 if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))
1905 haveDelegate++;
1906 break;
1907 case XML_CATA_NEXT_CATALOG:
1908 haveNext++;
1909 break;
1910 default:
1911 break;
1912 }
1913 cur = cur->next;
1914 }
1915 if (rewrite != NULL) {
1916 if (xmlDebugCatalogs)
1917 xmlGenericError(xmlGenericErrorContext,
1918 "Using rewriting rule %s\n", rewrite->name);
1919 ret = xmlStrdup(rewrite->URL);
1920 if (ret != NULL)
1921 ret = xmlStrcat(ret, &URI[lenrewrite]);
1922 return(ret);
1923 }
1924 if (haveDelegate) {
1925 const xmlChar *delegates[MAX_DELEGATE];
1926 int nbList = 0, i;
1927
1928 /*
1929 * Assume the entries have been sorted by decreasing substring
1930 * matches when the list was produced.
1931 */
1932 cur = catal;
1933 while (cur != NULL) {
1934 if (((cur->type == XML_CATA_DELEGATE_SYSTEM) ||
1935 (cur->type == XML_CATA_DELEGATE_URI)) &&
1936 (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) {
1937 for (i = 0;i < nbList;i++)
1938 if (xmlStrEqual(cur->URL, delegates[i]))
1939 break;
1940 if (i < nbList) {
1941 cur = cur->next;
1942 continue;
1943 }
1944 if (nbList < MAX_DELEGATE)
1945 delegates[nbList++] = cur->URL;
1946
1947 if (cur->children == NULL) {
1948 xmlFetchXMLCatalogFile(cur);
1949 }
1950 if (cur->children != NULL) {
1951 if (xmlDebugCatalogs)
1952 xmlGenericError(xmlGenericErrorContext,
1953 "Trying URI delegate %s\n", cur->URL);
1954 ret = xmlCatalogListXMLResolveURI(
1955 cur->children, URI);
1956 if (ret != NULL)
1957 return(ret);
1958 }
1959 }
1960 cur = cur->next;
1961 }
1962 /*
1963 * Apply the cut algorithm explained in 4/
1964 */
1965 return(XML_CATAL_BREAK);
1966 }
1967 if (haveNext) {
1968 cur = catal;
1969 while (cur != NULL) {
1970 if (cur->type == XML_CATA_NEXT_CATALOG) {
1971 if (cur->children == NULL) {
1972 xmlFetchXMLCatalogFile(cur);
1973 }
1974 if (cur->children != NULL) {
1975 ret = xmlCatalogListXMLResolveURI(cur->children, URI);
1976 if (ret != NULL)
1977 return(ret);
1978 }
1979 }
1980 cur = cur->next;
1981 }
1982 }
1983
1984 return(NULL);
1985}
1986
1987/**
1988 * xmlCatalogListXMLResolve:
1989 * @catal: a catalog list
1990 * @pubID: the public ID string
1991 * @sysID: the system ID string
1992 *
1993 * Do a complete resolution lookup of an External Identifier for a
1994 * list of catalogs
1995 *
1996 * Implements (or tries to) 7.1. External Identifier Resolution
1997 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
1998 *
1999 * Returns the URI of the resource or NULL if not found
2000 */
2001static xmlChar *
2002xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
2003 const xmlChar *sysID) {
2004 xmlChar *ret = NULL;
2005 xmlChar *urnID = NULL;
2006 xmlChar *normid;
2007
2008 if (catal == NULL)
2009 return(NULL);
2010 if ((pubID == NULL) && (sysID == NULL))
2011 return(NULL);
2012
2013 normid = xmlCatalogNormalizePublic(pubID);
2014 if (normid != NULL)
2015 pubID = (*normid != 0 ? normid : NULL);
2016
2017 if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2018 urnID = xmlCatalogUnWrapURN(pubID);
2019 if (xmlDebugCatalogs) {
2020 if (urnID == NULL)
2021 xmlGenericError(xmlGenericErrorContext,
2022 "Public URN ID %s expanded to NULL\n", pubID);
2023 else
2024 xmlGenericError(xmlGenericErrorContext,
2025 "Public URN ID expanded to %s\n", urnID);
2026 }
2027 ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
2028 if (urnID != NULL)
2029 xmlFree(urnID);
2030 if (normid != NULL)
2031 xmlFree(normid);
2032 return(ret);
2033 }
2034 if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2035 urnID = xmlCatalogUnWrapURN(sysID);
2036 if (xmlDebugCatalogs) {
2037 if (urnID == NULL)
2038 xmlGenericError(xmlGenericErrorContext,
2039 "System URN ID %s expanded to NULL\n", sysID);
2040 else
2041 xmlGenericError(xmlGenericErrorContext,
2042 "System URN ID expanded to %s\n", urnID);
2043 }
2044 if (pubID == NULL)
2045 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2046 else if (xmlStrEqual(pubID, urnID))
2047 ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
2048 else {
2049 ret = xmlCatalogListXMLResolve(catal, pubID, urnID);
2050 }
2051 if (urnID != NULL)
2052 xmlFree(urnID);
2053 if (normid != NULL)
2054 xmlFree(normid);
2055 return(ret);
2056 }
2057 while (catal != NULL) {
2058 if (catal->type == XML_CATA_CATALOG) {
2059 if (catal->children == NULL) {
2060 xmlFetchXMLCatalogFile(catal);
2061 }
2062 if (catal->children != NULL) {
2063 ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
2064 if (ret != NULL) {
2065 break;
2066 } else if ((catal->children != NULL) &&
2067 (catal->children->depth > MAX_CATAL_DEPTH)) {
2068 ret = NULL;
2069 break;
2070 }
2071 }
2072 }
2073 catal = catal->next;
2074 }
2075 if (normid != NULL)
2076 xmlFree(normid);
2077 return(ret);
2078}
2079
2080/**
2081 * xmlCatalogListXMLResolveURI:
2082 * @catal: a catalog list
2083 * @URI: the URI
2084 *
2085 * Do a complete resolution lookup of an URI for a list of catalogs
2086 *
2087 * Implements (or tries to) 7.2. URI Resolution
2088 * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
2089 *
2090 * Returns the URI of the resource or NULL if not found
2091 */
2092static xmlChar *
2093xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) {
2094 xmlChar *ret = NULL;
2095 xmlChar *urnID = NULL;
2096
2097 if (catal == NULL)
2098 return(NULL);
2099 if (URI == NULL)
2100 return(NULL);
2101
2102 if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
2103 urnID = xmlCatalogUnWrapURN(URI);
2104 if (xmlDebugCatalogs) {
2105 if (urnID == NULL)
2106 xmlGenericError(xmlGenericErrorContext,
2107 "URN ID %s expanded to NULL\n", URI);
2108 else
2109 xmlGenericError(xmlGenericErrorContext,
2110 "URN ID expanded to %s\n", urnID);
2111 }
2112 ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
2113 if (urnID != NULL)
2114 xmlFree(urnID);
2115 return(ret);
2116 }
2117 while (catal != NULL) {
2118 if (catal->type == XML_CATA_CATALOG) {
2119 if (catal->children == NULL) {
2120 xmlFetchXMLCatalogFile(catal);
2121 }
2122 if (catal->children != NULL) {
2123 ret = xmlCatalogXMLResolveURI(catal->children, URI);
2124 if (ret != NULL)
2125 return(ret);
2126 }
2127 }
2128 catal = catal->next;
2129 }
2130 return(ret);
2131}
2132
2133/************************************************************************
2134 * *
2135 * The SGML Catalog parser *
2136 * *
2137 ************************************************************************/
2138
2139
2140#define RAW *cur
2141#define NEXT cur++;
2142#define SKIP(x) cur += x;
2143
2144#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT;
2145
2146/**
2147 * xmlParseSGMLCatalogComment:
2148 * @cur: the current character
2149 *
2150 * Skip a comment in an SGML catalog
2151 *
2152 * Returns new current character
2153 */
2154static const xmlChar *
2155xmlParseSGMLCatalogComment(const xmlChar *cur) {
2156 if ((cur[0] != '-') || (cur[1] != '-'))
2157 return(cur);
2158 SKIP(2);
2159 while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-'))))
2160 NEXT;
2161 if (cur[0] == 0) {
2162 return(NULL);
2163 }
2164 return(cur + 2);
2165}
2166
2167/**
2168 * xmlParseSGMLCatalogPubid:
2169 * @cur: the current character
2170 * @id: the return location
2171 *
2172 * Parse an SGML catalog ID
2173 *
2174 * Returns new current character and store the value in @id
2175 */
2176static const xmlChar *
2177xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) {
2178 xmlChar *buf = NULL, *tmp;
2179 int len = 0;
2180 int size = 50;
2181 xmlChar stop;
2182 int count = 0;
2183
2184 *id = NULL;
2185
2186 if (RAW == '"') {
2187 NEXT;
2188 stop = '"';
2189 } else if (RAW == '\'') {
2190 NEXT;
2191 stop = '\'';
2192 } else {
2193 stop = ' ';
2194 }
2195 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
2196 if (buf == NULL) {
2197 xmlCatalogErrMemory("allocating public ID");
2198 return(NULL);
2199 }
2200 while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) {
2201 if ((*cur == stop) && (stop != ' '))
2202 break;
2203 if ((stop == ' ') && (IS_BLANK_CH(*cur)))
2204 break;
2205 if (len + 1 >= size) {
2206 size *= 2;
2207 tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
2208 if (tmp == NULL) {
2209 xmlCatalogErrMemory("allocating public ID");
2210 xmlFree(buf);
2211 return(NULL);
2212 }
2213 buf = tmp;
2214 }
2215 buf[len++] = *cur;
2216 count++;
2217 NEXT;
2218 }
2219 buf[len] = 0;
2220 if (stop == ' ') {
2221 if (!IS_BLANK_CH(*cur)) {
2222 xmlFree(buf);
2223 return(NULL);
2224 }
2225 } else {
2226 if (*cur != stop) {
2227 xmlFree(buf);
2228 return(NULL);
2229 }
2230 NEXT;
2231 }
2232 *id = buf;
2233 return(cur);
2234}
2235
2236/**
2237 * xmlParseSGMLCatalogName:
2238 * @cur: the current character
2239 * @name: the return location
2240 *
2241 * Parse an SGML catalog name
2242 *
2243 * Returns new current character and store the value in @name
2244 */
2245static const xmlChar *
2246xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) {
2247 xmlChar buf[XML_MAX_NAMELEN + 5];
2248 int len = 0;
2249 int c;
2250
2251 *name = NULL;
2252
2253 /*
2254 * Handler for more complex cases
2255 */
2256 c = *cur;
2257 if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) {
2258 return(NULL);
2259 }
2260
2261 while (((IS_LETTER(c)) || (IS_DIGIT(c)) ||
2262 (c == '.') || (c == '-') ||
2263 (c == '_') || (c == ':'))) {
2264 buf[len++] = c;
2265 cur++;
2266 c = *cur;
2267 if (len >= XML_MAX_NAMELEN)
2268 return(NULL);
2269 }
2270 *name = xmlStrndup(buf, len);
2271 return(cur);
2272}
2273
2274/**
2275 * xmlGetSGMLCatalogEntryType:
2276 * @name: the entry name
2277 *
2278 * Get the Catalog entry type for a given SGML Catalog name
2279 *
2280 * Returns Catalog entry type
2281 */
2282static xmlCatalogEntryType
2283xmlGetSGMLCatalogEntryType(const xmlChar *name) {
2284 xmlCatalogEntryType type = XML_CATA_NONE;
2285 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2286 type = SGML_CATA_SYSTEM;
2287 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2288 type = SGML_CATA_PUBLIC;
2289 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2290 type = SGML_CATA_DELEGATE;
2291 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2292 type = SGML_CATA_ENTITY;
2293 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2294 type = SGML_CATA_DOCTYPE;
2295 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2296 type = SGML_CATA_LINKTYPE;
2297 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2298 type = SGML_CATA_NOTATION;
2299 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2300 type = SGML_CATA_SGMLDECL;
2301 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2302 type = SGML_CATA_DOCUMENT;
2303 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2304 type = SGML_CATA_CATALOG;
2305 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2306 type = SGML_CATA_BASE;
2307 return(type);
2308}
2309
2310/**
2311 * xmlParseSGMLCatalog:
2312 * @catal: the SGML Catalog
2313 * @value: the content of the SGML Catalog serialization
2314 * @file: the filepath for the catalog
2315 * @super: should this be handled as a Super Catalog in which case
2316 * parsing is not recursive
2317 *
2318 * Parse an SGML catalog content and fill up the @catal hash table with
2319 * the new entries found.
2320 *
2321 * Returns 0 in case of success, -1 in case of error.
2322 */
2323static int
2324xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
2325 const char *file, int super) {
2326 const xmlChar *cur = value;
2327 xmlChar *base = NULL;
2328 int res;
2329
2330 if ((cur == NULL) || (file == NULL))
2331 return(-1);
2332 base = xmlStrdup((const xmlChar *) file);
2333
2334 while ((cur != NULL) && (cur[0] != 0)) {
2335 SKIP_BLANKS;
2336 if (cur[0] == 0)
2337 break;
2338 if ((cur[0] == '-') && (cur[1] == '-')) {
2339 cur = xmlParseSGMLCatalogComment(cur);
2340 if (cur == NULL) {
2341 /* error */
2342 break;
2343 }
2344 } else {
2345 xmlChar *sysid = NULL;
2346 xmlChar *name = NULL;
2347 xmlCatalogEntryType type = XML_CATA_NONE;
2348
2349 cur = xmlParseSGMLCatalogName(cur, &name);
2350 if (name == NULL) {
2351 /* error */
2352 break;
2353 }
2354 if (!IS_BLANK_CH(*cur)) {
2355 /* error */
2356 break;
2357 }
2358 SKIP_BLANKS;
2359 if (xmlStrEqual(name, (const xmlChar *) "SYSTEM"))
2360 type = SGML_CATA_SYSTEM;
2361 else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC"))
2362 type = SGML_CATA_PUBLIC;
2363 else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE"))
2364 type = SGML_CATA_DELEGATE;
2365 else if (xmlStrEqual(name, (const xmlChar *) "ENTITY"))
2366 type = SGML_CATA_ENTITY;
2367 else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE"))
2368 type = SGML_CATA_DOCTYPE;
2369 else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE"))
2370 type = SGML_CATA_LINKTYPE;
2371 else if (xmlStrEqual(name, (const xmlChar *) "NOTATION"))
2372 type = SGML_CATA_NOTATION;
2373 else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL"))
2374 type = SGML_CATA_SGMLDECL;
2375 else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT"))
2376 type = SGML_CATA_DOCUMENT;
2377 else if (xmlStrEqual(name, (const xmlChar *) "CATALOG"))
2378 type = SGML_CATA_CATALOG;
2379 else if (xmlStrEqual(name, (const xmlChar *) "BASE"))
2380 type = SGML_CATA_BASE;
2381 else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) {
2382 xmlFree(name);
2383 cur = xmlParseSGMLCatalogName(cur, &name);
2384 if (name == NULL) {
2385 /* error */
2386 break;
2387 }
2388 xmlFree(name);
2389 continue;
2390 }
2391 xmlFree(name);
2392 name = NULL;
2393
2394 switch(type) {
2395 case SGML_CATA_ENTITY:
2396 if (*cur == '%')
2397 type = SGML_CATA_PENTITY;
2398 case SGML_CATA_PENTITY:
2399 case SGML_CATA_DOCTYPE:
2400 case SGML_CATA_LINKTYPE:
2401 case SGML_CATA_NOTATION:
2402 cur = xmlParseSGMLCatalogName(cur, &name);
2403 if (cur == NULL) {
2404 /* error */
2405 break;
2406 }
2407 if (!IS_BLANK_CH(*cur)) {
2408 /* error */
2409 break;
2410 }
2411 SKIP_BLANKS;
2412 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2413 if (cur == NULL) {
2414 /* error */
2415 break;
2416 }
2417 break;
2418 case SGML_CATA_PUBLIC:
2419 case SGML_CATA_SYSTEM:
2420 case SGML_CATA_DELEGATE:
2421 cur = xmlParseSGMLCatalogPubid(cur, &name);
2422 if (cur == NULL) {
2423 /* error */
2424 break;
2425 }
2426 if (type != SGML_CATA_SYSTEM) {
2427 xmlChar *normid;
2428
2429 normid = xmlCatalogNormalizePublic(name);
2430 if (normid != NULL) {
2431 if (name != NULL)
2432 xmlFree(name);
2433 if (*normid != 0)
2434 name = normid;
2435 else {
2436 xmlFree(normid);
2437 name = NULL;
2438 }
2439 }
2440 }
2441 if (!IS_BLANK_CH(*cur)) {
2442 /* error */
2443 break;
2444 }
2445 SKIP_BLANKS;
2446 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2447 if (cur == NULL) {
2448 /* error */
2449 break;
2450 }
2451 break;
2452 case SGML_CATA_BASE:
2453 case SGML_CATA_CATALOG:
2454 case SGML_CATA_DOCUMENT:
2455 case SGML_CATA_SGMLDECL:
2456 cur = xmlParseSGMLCatalogPubid(cur, &sysid);
2457 if (cur == NULL) {
2458 /* error */
2459 break;
2460 }
2461 break;
2462 default:
2463 break;
2464 }
2465 if (cur == NULL) {
2466 if (name != NULL)
2467 xmlFree(name);
2468 if (sysid != NULL)
2469 xmlFree(sysid);
2470 break;
2471 } else if (type == SGML_CATA_BASE) {
2472 if (base != NULL)
2473 xmlFree(base);
2474 base = xmlStrdup(sysid);
2475 } else if ((type == SGML_CATA_PUBLIC) ||
2476 (type == SGML_CATA_SYSTEM)) {
2477 xmlChar *filename;
2478
2479 filename = xmlBuildURI(sysid, base);
2480 if (filename != NULL) {
2481 xmlCatalogEntryPtr entry;
2482
2483 entry = xmlNewCatalogEntry(type, name, filename,
2484 NULL, XML_CATA_PREFER_NONE, NULL);
2485 res = xmlHashAddEntry(catal->sgml, name, entry);
2486 if (res < 0) {
2487 xmlFreeCatalogEntry(entry);
2488 }
2489 xmlFree(filename);
2490 }
2491
2492 } else if (type == SGML_CATA_CATALOG) {
2493 if (super) {
2494 xmlCatalogEntryPtr entry;
2495
2496 entry = xmlNewCatalogEntry(type, sysid, NULL, NULL,
2497 XML_CATA_PREFER_NONE, NULL);
2498 res = xmlHashAddEntry(catal->sgml, sysid, entry);
2499 if (res < 0) {
2500 xmlFreeCatalogEntry(entry);
2501 }
2502 } else {
2503 xmlChar *filename;
2504
2505 filename = xmlBuildURI(sysid, base);
2506 if (filename != NULL) {
2507 xmlExpandCatalog(catal, (const char *)filename);
2508 xmlFree(filename);
2509 }
2510 }
2511 }
2512 /*
2513 * drop anything else we won't handle it
2514 */
2515 if (name != NULL)
2516 xmlFree(name);
2517 if (sysid != NULL)
2518 xmlFree(sysid);
2519 }
2520 }
2521 if (base != NULL)
2522 xmlFree(base);
2523 if (cur == NULL)
2524 return(-1);
2525 return(0);
2526}
2527
2528/************************************************************************
2529 * *
2530 * SGML Catalog handling *
2531 * *
2532 ************************************************************************/
2533
2534/**
2535 * xmlCatalogGetSGMLPublic:
2536 * @catal: an SGML catalog hash
2537 * @pubID: the public ID string
2538 *
2539 * Try to lookup the catalog local reference associated to a public ID
2540 *
2541 * Returns the local resource if found or NULL otherwise.
2542 */
2543static const xmlChar *
2544xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) {
2545 xmlCatalogEntryPtr entry;
2546 xmlChar *normid;
2547
2548 if (catal == NULL)
2549 return(NULL);
2550
2551 normid = xmlCatalogNormalizePublic(pubID);
2552 if (normid != NULL)
2553 pubID = (*normid != 0 ? normid : NULL);
2554
2555 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID);
2556 if (entry == NULL) {
2557 if (normid != NULL)
2558 xmlFree(normid);
2559 return(NULL);
2560 }
2561 if (entry->type == SGML_CATA_PUBLIC) {
2562 if (normid != NULL)
2563 xmlFree(normid);
2564 return(entry->URL);
2565 }
2566 if (normid != NULL)
2567 xmlFree(normid);
2568 return(NULL);
2569}
2570
2571/**
2572 * xmlCatalogGetSGMLSystem:
2573 * @catal: an SGML catalog hash
2574 * @sysID: the system ID string
2575 *
2576 * Try to lookup the catalog local reference for a system ID
2577 *
2578 * Returns the local resource if found or NULL otherwise.
2579 */
2580static const xmlChar *
2581xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
2582 xmlCatalogEntryPtr entry;
2583
2584 if (catal == NULL)
2585 return(NULL);
2586
2587 entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
2588 if (entry == NULL)
2589 return(NULL);
2590 if (entry->type == SGML_CATA_SYSTEM)
2591 return(entry->URL);
2592 return(NULL);
2593}
2594
2595/**
2596 * xmlCatalogSGMLResolve:
2597 * @catal: the SGML catalog
2598 * @pubID: the public ID string
2599 * @sysID: the system ID string
2600 *
2601 * Do a complete resolution lookup of an External Identifier
2602 *
2603 * Returns the URI of the resource or NULL if not found
2604 */
2605static const xmlChar *
2606xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID,
2607 const xmlChar *sysID) {
2608 const xmlChar *ret = NULL;
2609
2610 if (catal->sgml == NULL)
2611 return(NULL);
2612
2613 if (pubID != NULL)
2614 ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2615 if (ret != NULL)
2616 return(ret);
2617 if (sysID != NULL)
2618 ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2619 return(NULL);
2620}
2621
2622/************************************************************************
2623 * *
2624 * Specific Public interfaces *
2625 * *
2626 ************************************************************************/
2627
2628/**
2629 * xmlLoadSGMLSuperCatalog:
2630 * @filename: a file path
2631 *
2632 * Load an SGML super catalog. It won't expand CATALOG or DELEGATE
2633 * references. This is only needed for manipulating SGML Super Catalogs
2634 * like adding and removing CATALOG or DELEGATE entries.
2635 *
2636 * Returns the catalog parsed or NULL in case of error
2637 */
2638xmlCatalogPtr
2639xmlLoadSGMLSuperCatalog(const char *filename)
2640{
2641 xmlChar *content;
2642 xmlCatalogPtr catal;
2643 int ret;
2644
2645 content = xmlLoadFileContent(filename);
2646 if (content == NULL)
2647 return(NULL);
2648
2649 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2650 if (catal == NULL) {
2651 xmlFree(content);
2652 return(NULL);
2653 }
2654
2655 ret = xmlParseSGMLCatalog(catal, content, filename, 1);
2656 xmlFree(content);
2657 if (ret < 0) {
2658 xmlFreeCatalog(catal);
2659 return(NULL);
2660 }
2661 return (catal);
2662}
2663
2664/**
2665 * xmlLoadACatalog:
2666 * @filename: a file path
2667 *
2668 * Load the catalog and build the associated data structures.
2669 * This can be either an XML Catalog or an SGML Catalog
2670 * It will recurse in SGML CATALOG entries. On the other hand XML
2671 * Catalogs are not handled recursively.
2672 *
2673 * Returns the catalog parsed or NULL in case of error
2674 */
2675xmlCatalogPtr
2676xmlLoadACatalog(const char *filename)
2677{
2678 xmlChar *content;
2679 xmlChar *first;
2680 xmlCatalogPtr catal;
2681 int ret;
2682
2683 content = xmlLoadFileContent(filename);
2684 if (content == NULL)
2685 return(NULL);
2686
2687
2688 first = content;
2689
2690 while ((*first != 0) && (*first != '-') && (*first != '<') &&
2691 (!(((*first >= 'A') && (*first <= 'Z')) ||
2692 ((*first >= 'a') && (*first <= 'z')))))
2693 first++;
2694
2695 if (*first != '<') {
2696 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2697 if (catal == NULL) {
2698 xmlFree(content);
2699 return(NULL);
2700 }
2701 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2702 if (ret < 0) {
2703 xmlFreeCatalog(catal);
2704 xmlFree(content);
2705 return(NULL);
2706 }
2707 } else {
2708 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer);
2709 if (catal == NULL) {
2710 xmlFree(content);
2711 return(NULL);
2712 }
2713 catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2714 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
2715 }
2716 xmlFree(content);
2717 return (catal);
2718}
2719
2720/**
2721 * xmlExpandCatalog:
2722 * @catal: a catalog
2723 * @filename: a file path
2724 *
2725 * Load the catalog and expand the existing catal structure.
2726 * This can be either an XML Catalog or an SGML Catalog
2727 *
2728 * Returns 0 in case of success, -1 in case of error
2729 */
2730static int
2731xmlExpandCatalog(xmlCatalogPtr catal, const char *filename)
2732{
2733 int ret;
2734
2735 if ((catal == NULL) || (filename == NULL))
2736 return(-1);
2737
2738
2739 if (catal->type == XML_SGML_CATALOG_TYPE) {
2740 xmlChar *content;
2741
2742 content = xmlLoadFileContent(filename);
2743 if (content == NULL)
2744 return(-1);
2745
2746 ret = xmlParseSGMLCatalog(catal, content, filename, 0);
2747 if (ret < 0) {
2748 xmlFree(content);
2749 return(-1);
2750 }
2751 xmlFree(content);
2752 } else {
2753 xmlCatalogEntryPtr tmp, cur;
2754 tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
2755 NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL);
2756
2757 cur = catal->xml;
2758 if (cur == NULL) {
2759 catal->xml = tmp;
2760 } else {
2761 while (cur->next != NULL) cur = cur->next;
2762 cur->next = tmp;
2763 }
2764 }
2765 return (0);
2766}
2767
2768/**
2769 * xmlACatalogResolveSystem:
2770 * @catal: a Catalog
2771 * @sysID: the system ID string
2772 *
2773 * Try to lookup the catalog resource for a system ID
2774 *
2775 * Returns the resource if found or NULL otherwise, the value returned
2776 * must be freed by the caller.
2777 */
2778xmlChar *
2779xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) {
2780 xmlChar *ret = NULL;
2781
2782 if ((sysID == NULL) || (catal == NULL))
2783 return(NULL);
2784
2785 if (xmlDebugCatalogs)
2786 xmlGenericError(xmlGenericErrorContext,
2787 "Resolve sysID %s\n", sysID);
2788
2789 if (catal->type == XML_XML_CATALOG_TYPE) {
2790 ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID);
2791 if (ret == XML_CATAL_BREAK)
2792 ret = NULL;
2793 } else {
2794 const xmlChar *sgml;
2795
2796 sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID);
2797 if (sgml != NULL)
2798 ret = xmlStrdup(sgml);
2799 }
2800 return(ret);
2801}
2802
2803/**
2804 * xmlACatalogResolvePublic:
2805 * @catal: a Catalog
2806 * @pubID: the public ID string
2807 *
2808 * Try to lookup the catalog local reference associated to a public ID in that catalog
2809 *
2810 * Returns the local resource if found or NULL otherwise, the value returned
2811 * must be freed by the caller.
2812 */
2813xmlChar *
2814xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) {
2815 xmlChar *ret = NULL;
2816
2817 if ((pubID == NULL) || (catal == NULL))
2818 return(NULL);
2819
2820 if (xmlDebugCatalogs)
2821 xmlGenericError(xmlGenericErrorContext,
2822 "Resolve pubID %s\n", pubID);
2823
2824 if (catal->type == XML_XML_CATALOG_TYPE) {
2825 ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL);
2826 if (ret == XML_CATAL_BREAK)
2827 ret = NULL;
2828 } else {
2829 const xmlChar *sgml;
2830
2831 sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID);
2832 if (sgml != NULL)
2833 ret = xmlStrdup(sgml);
2834 }
2835 return(ret);
2836}
2837
2838/**
2839 * xmlACatalogResolve:
2840 * @catal: a Catalog
2841 * @pubID: the public ID string
2842 * @sysID: the system ID string
2843 *
2844 * Do a complete resolution lookup of an External Identifier
2845 *
2846 * Returns the URI of the resource or NULL if not found, it must be freed
2847 * by the caller.
2848 */
2849xmlChar *
2850xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
2851 const xmlChar * sysID)
2852{
2853 xmlChar *ret = NULL;
2854
2855 if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL))
2856 return (NULL);
2857
2858 if (xmlDebugCatalogs) {
2859 if ((pubID != NULL) && (sysID != NULL)) {
2860 xmlGenericError(xmlGenericErrorContext,
2861 "Resolve: pubID %s sysID %s\n", pubID, sysID);
2862 } else if (pubID != NULL) {
2863 xmlGenericError(xmlGenericErrorContext,
2864 "Resolve: pubID %s\n", pubID);
2865 } else {
2866 xmlGenericError(xmlGenericErrorContext,
2867 "Resolve: sysID %s\n", sysID);
2868 }
2869 }
2870
2871 if (catal->type == XML_XML_CATALOG_TYPE) {
2872 ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID);
2873 if (ret == XML_CATAL_BREAK)
2874 ret = NULL;
2875 } else {
2876 const xmlChar *sgml;
2877
2878 sgml = xmlCatalogSGMLResolve(catal, pubID, sysID);
2879 if (sgml != NULL)
2880 ret = xmlStrdup(sgml);
2881 }
2882 return (ret);
2883}
2884
2885/**
2886 * xmlACatalogResolveURI:
2887 * @catal: a Catalog
2888 * @URI: the URI
2889 *
2890 * Do a complete resolution lookup of an URI
2891 *
2892 * Returns the URI of the resource or NULL if not found, it must be freed
2893 * by the caller.
2894 */
2895xmlChar *
2896xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) {
2897 xmlChar *ret = NULL;
2898
2899 if ((URI == NULL) || (catal == NULL))
2900 return(NULL);
2901
2902 if (xmlDebugCatalogs)
2903 xmlGenericError(xmlGenericErrorContext,
2904 "Resolve URI %s\n", URI);
2905
2906 if (catal->type == XML_XML_CATALOG_TYPE) {
2907 ret = xmlCatalogListXMLResolveURI(catal->xml, URI);
2908 if (ret == XML_CATAL_BREAK)
2909 ret = NULL;
2910 } else {
2911 const xmlChar *sgml;
2912
2913 sgml = xmlCatalogSGMLResolve(catal, NULL, URI);
2914 if (sgml != NULL)
2915 sgml = xmlStrdup(sgml);
2916 }
2917 return(ret);
2918}
2919
2920#ifdef LIBXML_OUTPUT_ENABLED
2921/**
2922 * xmlACatalogDump:
2923 * @catal: a Catalog
2924 * @out: the file.
2925 *
2926 * Dump the given catalog to the given file.
2927 */
2928void
2929xmlACatalogDump(xmlCatalogPtr catal, FILE *out) {
2930 if ((out == NULL) || (catal == NULL))
2931 return;
2932
2933 if (catal->type == XML_XML_CATALOG_TYPE) {
2934 xmlDumpXMLCatalog(out, catal->xml);
2935 } else {
2936 xmlHashScan(catal->sgml,
2937 (xmlHashScanner) xmlCatalogDumpEntry, out);
2938 }
2939}
2940#endif /* LIBXML_OUTPUT_ENABLED */
2941
2942/**
2943 * xmlACatalogAdd:
2944 * @catal: a Catalog
2945 * @type: the type of record to add to the catalog
2946 * @orig: the system, public or prefix to match
2947 * @replace: the replacement value for the match
2948 *
2949 * Add an entry in the catalog, it may overwrite existing but
2950 * different entries.
2951 *
2952 * Returns 0 if successful, -1 otherwise
2953 */
2954int
2955xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type,
2956 const xmlChar * orig, const xmlChar * replace)
2957{
2958 int res = -1;
2959
2960 if (catal == NULL)
2961 return(-1);
2962
2963 if (catal->type == XML_XML_CATALOG_TYPE) {
2964 res = xmlAddXMLCatalog(catal->xml, type, orig, replace);
2965 } else {
2966 xmlCatalogEntryType cattype;
2967
2968 cattype = xmlGetSGMLCatalogEntryType(type);
2969 if (cattype != XML_CATA_NONE) {
2970 xmlCatalogEntryPtr entry;
2971
2972 entry = xmlNewCatalogEntry(cattype, orig, replace, NULL,
2973 XML_CATA_PREFER_NONE, NULL);
2974 if (catal->sgml == NULL)
2975 catal->sgml = xmlHashCreate(10);
2976 res = xmlHashAddEntry(catal->sgml, orig, entry);
2977 }
2978 }
2979 return (res);
2980}
2981
2982/**
2983 * xmlACatalogRemove:
2984 * @catal: a Catalog
2985 * @value: the value to remove
2986 *
2987 * Remove an entry from the catalog
2988 *
2989 * Returns the number of entries removed if successful, -1 otherwise
2990 */
2991int
2992xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) {
2993 int res = -1;
2994
2995 if ((catal == NULL) || (value == NULL))
2996 return(-1);
2997
2998 if (catal->type == XML_XML_CATALOG_TYPE) {
2999 res = xmlDelXMLCatalog(catal->xml, value);
3000 } else {
3001 res = xmlHashRemoveEntry(catal->sgml, value,
3002 (xmlHashDeallocator) xmlFreeCatalogEntry);
3003 if (res == 0)
3004 res = 1;
3005 }
3006 return(res);
3007}
3008
3009/**
3010 * xmlNewCatalog:
3011 * @sgml: should this create an SGML catalog
3012 *
3013 * create a new Catalog.
3014 *
3015 * Returns the xmlCatalogPtr or NULL in case of error
3016 */
3017xmlCatalogPtr
3018xmlNewCatalog(int sgml) {
3019 xmlCatalogPtr catal = NULL;
3020
3021 if (sgml) {
3022 catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE,
3023 xmlCatalogDefaultPrefer);
3024 if ((catal != NULL) && (catal->sgml == NULL))
3025 catal->sgml = xmlHashCreate(10);
3026 } else
3027 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3028 xmlCatalogDefaultPrefer);
3029 return(catal);
3030}
3031
3032/**
3033 * xmlCatalogIsEmpty:
3034 * @catal: should this create an SGML catalog
3035 *
3036 * Check is a catalog is empty
3037 *
3038 * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error.
3039 */
3040int
3041xmlCatalogIsEmpty(xmlCatalogPtr catal) {
3042 if (catal == NULL)
3043 return(-1);
3044
3045 if (catal->type == XML_XML_CATALOG_TYPE) {
3046 if (catal->xml == NULL)
3047 return(1);
3048 if ((catal->xml->type != XML_CATA_CATALOG) &&
3049 (catal->xml->type != XML_CATA_BROKEN_CATALOG))
3050 return(-1);
3051 if (catal->xml->children == NULL)
3052 return(1);
3053 return(0);
3054 } else {
3055 int res;
3056
3057 if (catal->sgml == NULL)
3058 return(1);
3059 res = xmlHashSize(catal->sgml);
3060 if (res == 0)
3061 return(1);
3062 if (res < 0)
3063 return(-1);
3064 }
3065 return(0);
3066}
3067
3068/************************************************************************
3069 * *
3070 * Public interfaces manipulating the global shared default catalog *
3071 * *
3072 ************************************************************************/
3073
3074/**
3075 * xmlInitializeCatalogData:
3076 *
3077 * Do the catalog initialization only of global data, doesn't try to load
3078 * any catalog actually.
3079 * this function is not thread safe, catalog initialization should
3080 * preferably be done once at startup
3081 */
3082static void
3083xmlInitializeCatalogData(void) {
3084 if (xmlCatalogInitialized != 0)
3085 return;
3086
3087 if (getenv("XML_DEBUG_CATALOG"))
3088 xmlDebugCatalogs = 1;
3089 xmlCatalogMutex = xmlNewRMutex();
3090
3091 xmlCatalogInitialized = 1;
3092}
3093/**
3094 * xmlInitializeCatalog:
3095 *
3096 * Do the catalog initialization.
3097 * this function is not thread safe, catalog initialization should
3098 * preferably be done once at startup
3099 */
3100void
3101xmlInitializeCatalog(void) {
3102 if (xmlCatalogInitialized != 0)
3103 return;
3104
3105 xmlInitializeCatalogData();
3106 xmlRMutexLock(xmlCatalogMutex);
3107
3108 if (getenv("XML_DEBUG_CATALOG"))
3109 xmlDebugCatalogs = 1;
3110
3111 if (xmlDefaultCatalog == NULL) {
3112 const char *catalogs;
3113 char *path;
3114 const char *cur, *paths;
3115 xmlCatalogPtr catal;
3116 xmlCatalogEntryPtr *nextent;
3117
3118 catalogs = (const char *) getenv("XML_CATALOG_FILES");
3119 if (catalogs == NULL)
3120#if defined(_WIN32) && defined(_MSC_VER)
3121 {
3122 void* hmodule;
3123 hmodule = GetModuleHandleA("libxml2.dll");
3124 if (hmodule == NULL)
3125 hmodule = GetModuleHandleA(NULL);
3126 if (hmodule != NULL) {
3127 char buf[256];
3128 unsigned long len = GetModuleFileNameA(hmodule, buf, 255);
3129 if (len != 0) {
3130 char* p = &(buf[len]);
3131 while (*p != '\\' && p > buf)
3132 p--;
3133 if (p != buf) {
3134 xmlChar* uri;
3135 strncpy(p, "\\..\\etc\\catalog", 255 - (p - buf));
3136 uri = xmlCanonicPath(buf);
3137 if (uri != NULL) {
3138 strncpy(XML_XML_DEFAULT_CATALOG, uri, 255);
3139 xmlFree(uri);
3140 }
3141 }
3142 }
3143 }
3144 catalogs = XML_XML_DEFAULT_CATALOG;
3145 }
3146#else
3147 catalogs = XML_XML_DEFAULT_CATALOG;
3148#endif
3149
3150 catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3151 xmlCatalogDefaultPrefer);
3152 if (catal != NULL) {
3153 /* the XML_CATALOG_FILES envvar is allowed to contain a
3154 space-separated list of entries. */
3155 cur = catalogs;
3156 nextent = &catal->xml;
3157 while (*cur != '\0') {
3158 while (xmlIsBlank_ch(*cur))
3159 cur++;
3160 if (*cur != 0) {
3161 paths = cur;
3162 while ((*cur != 0) && (!xmlIsBlank_ch(*cur)))
3163 cur++;
3164 path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths);
3165 if (path != NULL) {
3166 *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3167 NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL);
3168 if (*nextent != NULL)
3169 nextent = &((*nextent)->next);
3170 xmlFree(path);
3171 }
3172 }
3173 }
3174 xmlDefaultCatalog = catal;
3175 }
3176 }
3177
3178 xmlRMutexUnlock(xmlCatalogMutex);
3179}
3180
3181
3182/**
3183 * xmlLoadCatalog:
3184 * @filename: a file path
3185 *
3186 * Load the catalog and makes its definitions effective for the default
3187 * external entity loader. It will recurse in SGML CATALOG entries.
3188 * this function is not thread safe, catalog initialization should
3189 * preferably be done once at startup
3190 *
3191 * Returns 0 in case of success -1 in case of error
3192 */
3193int
3194xmlLoadCatalog(const char *filename)
3195{
3196 int ret;
3197 xmlCatalogPtr catal;
3198
3199 if (!xmlCatalogInitialized)
3200 xmlInitializeCatalogData();
3201
3202 xmlRMutexLock(xmlCatalogMutex);
3203
3204 if (xmlDefaultCatalog == NULL) {
3205 catal = xmlLoadACatalog(filename);
3206 if (catal == NULL) {
3207 xmlRMutexUnlock(xmlCatalogMutex);
3208 return(-1);
3209 }
3210
3211 xmlDefaultCatalog = catal;
3212 xmlRMutexUnlock(xmlCatalogMutex);
3213 return(0);
3214 }
3215
3216 ret = xmlExpandCatalog(xmlDefaultCatalog, filename);
3217 xmlRMutexUnlock(xmlCatalogMutex);
3218 return(ret);
3219}
3220
3221/**
3222 * xmlLoadCatalogs:
3223 * @pathss: a list of directories separated by a colon or a space.
3224 *
3225 * Load the catalogs and makes their definitions effective for the default
3226 * external entity loader.
3227 * this function is not thread safe, catalog initialization should
3228 * preferably be done once at startup
3229 */
3230void
3231xmlLoadCatalogs(const char *pathss) {
3232 const char *cur;
3233 const char *paths;
3234 xmlChar *path;
3235#ifdef _WIN32
3236 int i, iLen;
3237#endif
3238
3239 if (pathss == NULL)
3240 return;
3241
3242 cur = pathss;
3243 while (*cur != 0) {
3244 while (xmlIsBlank_ch(*cur)) cur++;
3245 if (*cur != 0) {
3246 paths = cur;
3247 while ((*cur != 0) && (*cur != PATH_SEAPARATOR) && (!xmlIsBlank_ch(*cur)))
3248 cur++;
3249 path = xmlStrndup((const xmlChar *)paths, cur - paths);
3250#ifdef _WIN32
3251 iLen = strlen(path);
3252 for(i = 0; i < iLen; i++) {
3253 if(path[i] == '\\') {
3254 path[i] = '/';
3255 }
3256 }
3257#endif
3258 if (path != NULL) {
3259 xmlLoadCatalog((const char *) path);
3260 xmlFree(path);
3261 }
3262 }
3263 while (*cur == PATH_SEAPARATOR)
3264 cur++;
3265 }
3266}
3267
3268/**
3269 * xmlCatalogCleanup:
3270 *
3271 * Free up all the memory associated with catalogs
3272 */
3273void
3274xmlCatalogCleanup(void) {
3275 if (xmlCatalogInitialized == 0)
3276 return;
3277
3278 xmlRMutexLock(xmlCatalogMutex);
3279 if (xmlDebugCatalogs)
3280 xmlGenericError(xmlGenericErrorContext,
3281 "Catalogs cleanup\n");
3282 if (xmlCatalogXMLFiles != NULL)
3283 xmlHashFree(xmlCatalogXMLFiles,
3284 (xmlHashDeallocator)xmlFreeCatalogHashEntryList);
3285 xmlCatalogXMLFiles = NULL;
3286 if (xmlDefaultCatalog != NULL)
3287 xmlFreeCatalog(xmlDefaultCatalog);
3288 xmlDefaultCatalog = NULL;
3289 xmlDebugCatalogs = 0;
3290 xmlCatalogInitialized = 0;
3291 xmlRMutexUnlock(xmlCatalogMutex);
3292 xmlFreeRMutex(xmlCatalogMutex);
3293}
3294
3295/**
3296 * xmlCatalogResolveSystem:
3297 * @sysID: the system ID string
3298 *
3299 * Try to lookup the catalog resource for a system ID
3300 *
3301 * Returns the resource if found or NULL otherwise, the value returned
3302 * must be freed by the caller.
3303 */
3304xmlChar *
3305xmlCatalogResolveSystem(const xmlChar *sysID) {
3306 xmlChar *ret;
3307
3308 if (!xmlCatalogInitialized)
3309 xmlInitializeCatalog();
3310
3311 ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID);
3312 return(ret);
3313}
3314
3315/**
3316 * xmlCatalogResolvePublic:
3317 * @pubID: the public ID string
3318 *
3319 * Try to lookup the catalog reference associated to a public ID
3320 *
3321 * Returns the resource if found or NULL otherwise, the value returned
3322 * must be freed by the caller.
3323 */
3324xmlChar *
3325xmlCatalogResolvePublic(const xmlChar *pubID) {
3326 xmlChar *ret;
3327
3328 if (!xmlCatalogInitialized)
3329 xmlInitializeCatalog();
3330
3331 ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID);
3332 return(ret);
3333}
3334
3335/**
3336 * xmlCatalogResolve:
3337 * @pubID: the public ID string
3338 * @sysID: the system ID string
3339 *
3340 * Do a complete resolution lookup of an External Identifier
3341 *
3342 * Returns the URI of the resource or NULL if not found, it must be freed
3343 * by the caller.
3344 */
3345xmlChar *
3346xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
3347 xmlChar *ret;
3348
3349 if (!xmlCatalogInitialized)
3350 xmlInitializeCatalog();
3351
3352 ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID);
3353 return(ret);
3354}
3355
3356/**
3357 * xmlCatalogResolveURI:
3358 * @URI: the URI
3359 *
3360 * Do a complete resolution lookup of an URI
3361 *
3362 * Returns the URI of the resource or NULL if not found, it must be freed
3363 * by the caller.
3364 */
3365xmlChar *
3366xmlCatalogResolveURI(const xmlChar *URI) {
3367 xmlChar *ret;
3368
3369 if (!xmlCatalogInitialized)
3370 xmlInitializeCatalog();
3371
3372 ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI);
3373 return(ret);
3374}
3375
3376#ifdef LIBXML_OUTPUT_ENABLED
3377/**
3378 * xmlCatalogDump:
3379 * @out: the file.
3380 *
3381 * Dump all the global catalog content to the given file.
3382 */
3383void
3384xmlCatalogDump(FILE *out) {
3385 if (out == NULL)
3386 return;
3387
3388 if (!xmlCatalogInitialized)
3389 xmlInitializeCatalog();
3390
3391 xmlACatalogDump(xmlDefaultCatalog, out);
3392}
3393#endif /* LIBXML_OUTPUT_ENABLED */
3394
3395/**
3396 * xmlCatalogAdd:
3397 * @type: the type of record to add to the catalog
3398 * @orig: the system, public or prefix to match
3399 * @replace: the replacement value for the match
3400 *
3401 * Add an entry in the catalog, it may overwrite existing but
3402 * different entries.
3403 * If called before any other catalog routine, allows to override the
3404 * default shared catalog put in place by xmlInitializeCatalog();
3405 *
3406 * Returns 0 if successful, -1 otherwise
3407 */
3408int
3409xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
3410 int res = -1;
3411
3412 if (!xmlCatalogInitialized)
3413 xmlInitializeCatalogData();
3414
3415 xmlRMutexLock(xmlCatalogMutex);
3416 /*
3417 * Specific case where one want to override the default catalog
3418 * put in place by xmlInitializeCatalog();
3419 */
3420 if ((xmlDefaultCatalog == NULL) &&
3421 (xmlStrEqual(type, BAD_CAST "catalog"))) {
3422 xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
3423 xmlCatalogDefaultPrefer);
3424 xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
3425 orig, NULL, xmlCatalogDefaultPrefer, NULL);
3426
3427 xmlRMutexUnlock(xmlCatalogMutex);
3428 return(0);
3429 }
3430
3431 res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace);
3432 xmlRMutexUnlock(xmlCatalogMutex);
3433 return(res);
3434}
3435
3436/**
3437 * xmlCatalogRemove:
3438 * @value: the value to remove
3439 *
3440 * Remove an entry from the catalog
3441 *
3442 * Returns the number of entries removed if successful, -1 otherwise
3443 */
3444int
3445xmlCatalogRemove(const xmlChar *value) {
3446 int res;
3447
3448 if (!xmlCatalogInitialized)
3449 xmlInitializeCatalog();
3450
3451 xmlRMutexLock(xmlCatalogMutex);
3452 res = xmlACatalogRemove(xmlDefaultCatalog, value);
3453 xmlRMutexUnlock(xmlCatalogMutex);
3454 return(res);
3455}
3456
3457/**
3458 * xmlCatalogConvert:
3459 *
3460 * Convert all the SGML catalog entries as XML ones
3461 *
3462 * Returns the number of entries converted if successful, -1 otherwise
3463 */
3464int
3465xmlCatalogConvert(void) {
3466 int res = -1;
3467
3468 if (!xmlCatalogInitialized)
3469 xmlInitializeCatalog();
3470
3471 xmlRMutexLock(xmlCatalogMutex);
3472 res = xmlConvertSGMLCatalog(xmlDefaultCatalog);
3473 xmlRMutexUnlock(xmlCatalogMutex);
3474 return(res);
3475}
3476
3477/************************************************************************
3478 * *
3479 * Public interface manipulating the common preferences *
3480 * *
3481 ************************************************************************/
3482
3483/**
3484 * xmlCatalogGetDefaults:
3485 *
3486 * Used to get the user preference w.r.t. to what catalogs should
3487 * be accepted
3488 *
3489 * Returns the current xmlCatalogAllow value
3490 */
3491xmlCatalogAllow
3492xmlCatalogGetDefaults(void) {
3493 return(xmlCatalogDefaultAllow);
3494}
3495
3496/**
3497 * xmlCatalogSetDefaults:
3498 * @allow: what catalogs should be accepted
3499 *
3500 * Used to set the user preference w.r.t. to what catalogs should
3501 * be accepted
3502 */
3503void
3504xmlCatalogSetDefaults(xmlCatalogAllow allow) {
3505 if (xmlDebugCatalogs) {
3506 switch (allow) {
3507 case XML_CATA_ALLOW_NONE:
3508 xmlGenericError(xmlGenericErrorContext,
3509 "Disabling catalog usage\n");
3510 break;
3511 case XML_CATA_ALLOW_GLOBAL:
3512 xmlGenericError(xmlGenericErrorContext,
3513 "Allowing only global catalogs\n");
3514 break;
3515 case XML_CATA_ALLOW_DOCUMENT:
3516 xmlGenericError(xmlGenericErrorContext,
3517 "Allowing only catalogs from the document\n");
3518 break;
3519 case XML_CATA_ALLOW_ALL:
3520 xmlGenericError(xmlGenericErrorContext,
3521 "Allowing all catalogs\n");
3522 break;
3523 }
3524 }
3525 xmlCatalogDefaultAllow = allow;
3526}
3527
3528/**
3529 * xmlCatalogSetDefaultPrefer:
3530 * @prefer: the default preference for delegation
3531 *
3532 * Allows to set the preference between public and system for deletion
3533 * in XML Catalog resolution. C.f. section 4.1.1 of the spec
3534 * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
3535 *
3536 * Returns the previous value of the default preference for delegation
3537 */
3538xmlCatalogPrefer
3539xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
3540 xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
3541
3542 if (prefer == XML_CATA_PREFER_NONE)
3543 return(ret);
3544
3545 if (xmlDebugCatalogs) {
3546 switch (prefer) {
3547 case XML_CATA_PREFER_PUBLIC:
3548 xmlGenericError(xmlGenericErrorContext,
3549 "Setting catalog preference to PUBLIC\n");
3550 break;
3551 case XML_CATA_PREFER_SYSTEM:
3552 xmlGenericError(xmlGenericErrorContext,
3553 "Setting catalog preference to SYSTEM\n");
3554 break;
3555 case XML_CATA_PREFER_NONE:
3556 break;
3557 }
3558 }
3559 xmlCatalogDefaultPrefer = prefer;
3560 return(ret);
3561}
3562
3563/**
3564 * xmlCatalogSetDebug:
3565 * @level: the debug level of catalogs required
3566 *
3567 * Used to set the debug level for catalog operation, 0 disable
3568 * debugging, 1 enable it
3569 *
3570 * Returns the previous value of the catalog debugging level
3571 */
3572int
3573xmlCatalogSetDebug(int level) {
3574 int ret = xmlDebugCatalogs;
3575
3576 if (level <= 0)
3577 xmlDebugCatalogs = 0;
3578 else
3579 xmlDebugCatalogs = level;
3580 return(ret);
3581}
3582
3583/************************************************************************
3584 * *
3585 * Minimal interfaces used for per-document catalogs by the parser *
3586 * *
3587 ************************************************************************/
3588
3589/**
3590 * xmlCatalogFreeLocal:
3591 * @catalogs: a document's list of catalogs
3592 *
3593 * Free up the memory associated to the catalog list
3594 */
3595void
3596xmlCatalogFreeLocal(void *catalogs) {
3597 xmlCatalogEntryPtr catal;
3598
3599 if (!xmlCatalogInitialized)
3600 xmlInitializeCatalog();
3601
3602 catal = (xmlCatalogEntryPtr) catalogs;
3603 if (catal != NULL)
3604 xmlFreeCatalogEntryList(catal);
3605}
3606
3607
3608/**
3609 * xmlCatalogAddLocal:
3610 * @catalogs: a document's list of catalogs
3611 * @URL: the URL to a new local catalog
3612 *
3613 * Add the new entry to the catalog list
3614 *
3615 * Returns the updated list
3616 */
3617void *
3618xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
3619 xmlCatalogEntryPtr catal, add;
3620
3621 if (!xmlCatalogInitialized)
3622 xmlInitializeCatalog();
3623
3624 if (URL == NULL)
3625 return(catalogs);
3626
3627 if (xmlDebugCatalogs)
3628 xmlGenericError(xmlGenericErrorContext,
3629 "Adding document catalog %s\n", URL);
3630
3631 add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL,
3632 xmlCatalogDefaultPrefer, NULL);
3633 if (add == NULL)
3634 return(catalogs);
3635
3636 catal = (xmlCatalogEntryPtr) catalogs;
3637 if (catal == NULL)
3638 return((void *) add);
3639
3640 while (catal->next != NULL)
3641 catal = catal->next;
3642 catal->next = add;
3643 return(catalogs);
3644}
3645
3646/**
3647 * xmlCatalogLocalResolve:
3648 * @catalogs: a document's list of catalogs
3649 * @pubID: the public ID string
3650 * @sysID: the system ID string
3651 *
3652 * Do a complete resolution lookup of an External Identifier using a
3653 * document's private catalog list
3654 *
3655 * Returns the URI of the resource or NULL if not found, it must be freed
3656 * by the caller.
3657 */
3658xmlChar *
3659xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
3660 const xmlChar *sysID) {
3661 xmlCatalogEntryPtr catal;
3662 xmlChar *ret;
3663
3664 if (!xmlCatalogInitialized)
3665 xmlInitializeCatalog();
3666
3667 if ((pubID == NULL) && (sysID == NULL))
3668 return(NULL);
3669
3670 if (xmlDebugCatalogs) {
3671 if ((pubID != NULL) && (sysID != NULL)) {
3672 xmlGenericError(xmlGenericErrorContext,
3673 "Local Resolve: pubID %s sysID %s\n", pubID, sysID);
3674 } else if (pubID != NULL) {
3675 xmlGenericError(xmlGenericErrorContext,
3676 "Local Resolve: pubID %s\n", pubID);
3677 } else {
3678 xmlGenericError(xmlGenericErrorContext,
3679 "Local Resolve: sysID %s\n", sysID);
3680 }
3681 }
3682
3683 catal = (xmlCatalogEntryPtr) catalogs;
3684 if (catal == NULL)
3685 return(NULL);
3686 ret = xmlCatalogListXMLResolve(catal, pubID, sysID);
3687 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3688 return(ret);
3689 return(NULL);
3690}
3691
3692/**
3693 * xmlCatalogLocalResolveURI:
3694 * @catalogs: a document's list of catalogs
3695 * @URI: the URI
3696 *
3697 * Do a complete resolution lookup of an URI using a
3698 * document's private catalog list
3699 *
3700 * Returns the URI of the resource or NULL if not found, it must be freed
3701 * by the caller.
3702 */
3703xmlChar *
3704xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) {
3705 xmlCatalogEntryPtr catal;
3706 xmlChar *ret;
3707
3708 if (!xmlCatalogInitialized)
3709 xmlInitializeCatalog();
3710
3711 if (URI == NULL)
3712 return(NULL);
3713
3714 if (xmlDebugCatalogs)
3715 xmlGenericError(xmlGenericErrorContext,
3716 "Resolve URI %s\n", URI);
3717
3718 catal = (xmlCatalogEntryPtr) catalogs;
3719 if (catal == NULL)
3720 return(NULL);
3721 ret = xmlCatalogListXMLResolveURI(catal, URI);
3722 if ((ret != NULL) && (ret != XML_CATAL_BREAK))
3723 return(ret);
3724 return(NULL);
3725}
3726
3727/************************************************************************
3728 * *
3729 * Deprecated interfaces *
3730 * *
3731 ************************************************************************/
3732/**
3733 * xmlCatalogGetSystem:
3734 * @sysID: the system ID string
3735 *
3736 * Try to lookup the catalog reference associated to a system ID
3737 * DEPRECATED, use xmlCatalogResolveSystem()
3738 *
3739 * Returns the resource if found or NULL otherwise.
3740 */
3741const xmlChar *
3742xmlCatalogGetSystem(const xmlChar *sysID) {
3743 xmlChar *ret;
3744 static xmlChar result[1000];
3745 static int msg = 0;
3746
3747 if (!xmlCatalogInitialized)
3748 xmlInitializeCatalog();
3749
3750 if (msg == 0) {
3751 xmlGenericError(xmlGenericErrorContext,
3752 "Use of deprecated xmlCatalogGetSystem() call\n");
3753 msg++;
3754 }
3755
3756 if (sysID == NULL)
3757 return(NULL);
3758
3759 /*
3760 * Check first the XML catalogs
3761 */
3762 if (xmlDefaultCatalog != NULL) {
3763 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID);
3764 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3765 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3766 result[sizeof(result) - 1] = 0;
3767 return(result);
3768 }
3769 }
3770
3771 if (xmlDefaultCatalog != NULL)
3772 return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID));
3773 return(NULL);
3774}
3775
3776/**
3777 * xmlCatalogGetPublic:
3778 * @pubID: the public ID string
3779 *
3780 * Try to lookup the catalog reference associated to a public ID
3781 * DEPRECATED, use xmlCatalogResolvePublic()
3782 *
3783 * Returns the resource if found or NULL otherwise.
3784 */
3785const xmlChar *
3786xmlCatalogGetPublic(const xmlChar *pubID) {
3787 xmlChar *ret;
3788 static xmlChar result[1000];
3789 static int msg = 0;
3790
3791 if (!xmlCatalogInitialized)
3792 xmlInitializeCatalog();
3793
3794 if (msg == 0) {
3795 xmlGenericError(xmlGenericErrorContext,
3796 "Use of deprecated xmlCatalogGetPublic() call\n");
3797 msg++;
3798 }
3799
3800 if (pubID == NULL)
3801 return(NULL);
3802
3803 /*
3804 * Check first the XML catalogs
3805 */
3806 if (xmlDefaultCatalog != NULL) {
3807 ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL);
3808 if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
3809 snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
3810 result[sizeof(result) - 1] = 0;
3811 return(result);
3812 }
3813 }
3814
3815 if (xmlDefaultCatalog != NULL)
3816 return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID));
3817 return(NULL);
3818}
3819
3820#define bottom_catalog
3821#include "elfgcchack.h"
3822#endif /* LIBXML_CATALOG_ENABLED */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette