VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/catalog.c@ 104106

Last change on this file since 104106 was 104106, checked in by vboxsync, 2 months ago

libxml2-2.9.14: Applied and adjusted our libxml2 changes to 2.9.14. bugref:10640

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

© 2023 Oracle
ContactPrivacy policyTerms of Use