VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/catalog.c@ 105420

Last change on this file since 105420 was 105420, checked in by vboxsync, 9 months ago

libxml2-2.12.6: Applied and adjusted our libxml2 changes to 2.12.6. bugref:10730

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

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