VirtualBox

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

最後變更 在這個檔案從106165是 105448,由 vboxsync 提交於 4 月 前

libxml2-2.13.2: builds and runs on Linux. bugref:10730

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

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