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