VirtualBox

source: vbox/trunk/src/libs/libxml2-2.9.14/catalog.c@ 98103

Last change on this file since 98103 was 95312, checked in by vboxsync, 2 years ago

libs/{curl,libxml2}: OSE export fixes, bugref:8515

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

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