Newer
Older
* catalog.c: set of generic Catalog related routines
*
* Reference: SGML Open Technical Resolution TR9401:1997.
* http://www.jclark.com/sp/catalog.htm
*
* XML Catalogs Working Draft 06 August 2001
* http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
*
* See Copyright for the status of this software.
*
* Daniel.Veillard@imag.fr
*/
#define IN_LIBXML
#include "libxml.h"
#ifdef LIBXML_CATALOG_ENABLED
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <libxml/xmlmemory.h>
#include <libxml/hash.h>
#include <libxml/uri.h>
#include <libxml/parserInternals.h>
#include <libxml/catalog.h>
#include <libxml/xmlerror.h>
#include <libxml/threads.h>
#include <libxml/globals.h>
#define MAX_DELEGATE 50
#define MAX_CATAL_DEPTH 50
#ifdef _WIN32
#else
#endif
/**
* TODO:
*
* macro to flag unimplemented blocks
* XML_CATALOG_PREFER user env to select between system/public preferred
* option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
*> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
*> values "system" and "public". I have made the default be "system" to
*> match yours.
*/
xmlGenericError(xmlGenericErrorContext, \
"Unimplemented block at %s:%d\n", \
__FILE__, __LINE__);
#define XML_URN_PUBID "urn:publicid:"
#define XML_CATAL_BREAK ((xmlChar *) -1)
#ifndef XML_XML_DEFAULT_CATALOG
#define XML_XML_DEFAULT_CATALOG "file://" SYSCONFDIR "/xml/catalog"
#endif
#ifndef XML_SGML_DEFAULT_CATALOG
#define XML_SGML_DEFAULT_CATALOG "file://" SYSCONFDIR "/sgml/catalog"
#endif
#if defined(_WIN32) && defined(_MSC_VER)
#undef XML_XML_DEFAULT_CATALOG
static char XML_XML_DEFAULT_CATALOG[256] = "file://" SYSCONFDIR "/xml/catalog";
void* __stdcall GetModuleHandleA(const char*);
unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long);
#endif
#endif
static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID);
static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
/************************************************************************
* *
* Types, all private *
* *
************************************************************************/
typedef enum {
XML_CATA_REMOVED = -1,
XML_CATA_NONE = 0,
XML_CATA_CATALOG,
XML_CATA_BROKEN_CATALOG,
XML_CATA_NEXT_CATALOG,
XML_CATA_GROUP,
XML_CATA_PUBLIC,
XML_CATA_SYSTEM,
XML_CATA_REWRITE_SYSTEM,
XML_CATA_DELEGATE_PUBLIC,
XML_CATA_DELEGATE_SYSTEM,
XML_CATA_URI,
XML_CATA_REWRITE_URI,
XML_CATA_DELEGATE_URI,
SGML_CATA_SYSTEM,
SGML_CATA_PUBLIC,
SGML_CATA_ENTITY,
SGML_CATA_PENTITY,
SGML_CATA_DOCTYPE,
SGML_CATA_LINKTYPE,
SGML_CATA_NOTATION,
SGML_CATA_DELEGATE,
SGML_CATA_BASE,
SGML_CATA_CATALOG,
SGML_CATA_DOCUMENT,
SGML_CATA_SGMLDECL
} xmlCatalogEntryType;
typedef struct _xmlCatalogEntry xmlCatalogEntry;
typedef xmlCatalogEntry *xmlCatalogEntryPtr;
struct _xmlCatalogEntry {
struct _xmlCatalogEntry *next;
struct _xmlCatalogEntry *parent;
struct _xmlCatalogEntry *children;
xmlCatalogEntryType type;
xmlChar *name;
xmlChar *value;
xmlChar *URL; /* The expanded URL using the base */
xmlCatalogPrefer prefer;
int dealloc;
int depth;
struct _xmlCatalogEntry *group;
};
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
typedef enum {
XML_XML_CATALOG_TYPE = 1,
XML_SGML_CATALOG_TYPE
} xmlCatalogType;
#define XML_MAX_SGML_CATA_DEPTH 10
struct _xmlCatalog {
xmlCatalogType type; /* either XML or SGML */
/*
* SGML Catalogs are stored as a simple hash table of catalog entries
* Catalog stack to check against overflows when building the
* SGML catalog
*/
char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */
int catalNr; /* Number of current catal streams */
int catalMax; /* Max number of catal streams */
xmlHashTablePtr sgml;
/*
* XML Catalogs are stored as a tree of Catalog entries
*/
xmlCatalogPrefer prefer;
xmlCatalogEntryPtr xml;
};
/************************************************************************
* *
* Global variables *
* *
************************************************************************/
/*
* Those are preferences
*/
static int xmlDebugCatalogs = 0; /* used for debugging */
static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC;
/*
* Hash table containing all the trees of XML catalogs parsed by
* the application.
*/
static xmlHashTablePtr xmlCatalogXMLFiles = NULL;
/*
* The default catalog in use by the application
*/
static xmlCatalogPtr xmlDefaultCatalog = NULL;
/*
* A mutex for modifying the shared global catalog(s)
* xmlDefaultCatalog tree.
* It also protects xmlCatalogXMLFiles
* The core of this readers/writer scheme is in xmlFetchXMLCatalogFile()
*/
static xmlRMutexPtr xmlCatalogMutex = NULL;
/*
* Whether the catalog support was initialized.
*/
static int xmlCatalogInitialized = 0;
/************************************************************************
* *
* *
************************************************************************/
/**
* xmlCatalogErrMemory:
*
* Handle an out of memory condition
*/
static void
xmlCatalogErrMemory(const char *extra)
{
__xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG,
XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
extra, NULL, NULL, 0, 0,
"Memory allocation failed : %s\n", extra);
}
/**
* xmlCatalogErr:
* @catal: the Catalog entry
* @node: the context node
* @msg: the error message
*
* Handle a catalog error
*/
static void LIBXML_ATTR_FORMAT(4,0)
xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error,
const char *msg, const xmlChar *str1, const xmlChar *str2,
const xmlChar *str3)
{
__xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG,
error, XML_ERR_ERROR, NULL, 0,
(const char *) str1, (const char *) str2,
(const char *) str3, 0, 0,
msg, str1, str2, str3);
}
/************************************************************************
* *
* Allocation and Freeing *
* *
************************************************************************/
/**
* xmlNewCatalogEntry:
* @type: type of entry
* @name: name of the entry
* @value: value of the entry
* @prefer: the PUBLIC vs. SYSTEM current preference value
* @group: for members of a group, the group entry
*
* create a new Catalog entry, this type is shared both by XML and
* SGML catalogs, but the acceptable types values differs.
*
* Returns the xmlCatalogEntryPtr or NULL in case of error
*/
static xmlCatalogEntryPtr
xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer,
xmlCatalogEntryPtr group) {
xmlCatalogEntryPtr ret;
xmlChar *normid = NULL;
ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
if (ret == NULL) {
xmlCatalogErrMemory("allocating catalog entry");
return(NULL);
}
ret->next = NULL;
ret->parent = NULL;
ret->children = NULL;
ret->type = type;
if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) {
normid = xmlCatalogNormalizePublic(name);
if (normid != NULL)
name = (*normid != 0 ? normid : NULL);
}
if (name != NULL)
ret->name = xmlStrdup(name);
else
ret->name = NULL;
if (normid != NULL)
xmlFree(normid);
if (value != NULL)
ret->value = xmlStrdup(value);
else
ret->value = NULL;
if (URL == NULL)
URL = value;
if (URL != NULL)
ret->URL = xmlStrdup(URL);
else
ret->URL = NULL;
ret->prefer = prefer;
ret->dealloc = 0;
ret->depth = 0;
ret->group = group;
return(ret);
}
static void
xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret);
/**
* xmlFreeCatalogEntry:
*
* Free the memory allocated to a Catalog entry
*/
static void
xmlFreeCatalogEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
xmlCatalogEntryPtr ret = (xmlCatalogEntryPtr) payload;
if (ret == NULL)
return;
/*
* Entries stored in the file hash must be deallocated
* only by the file hash cleaner !
*/
if (ret->dealloc == 1)
return;
if (xmlDebugCatalogs) {
if (ret->name != NULL)
xmlGenericError(xmlGenericErrorContext,
"Free catalog entry %s\n", ret->name);
else if (ret->value != NULL)
xmlGenericError(xmlGenericErrorContext,
"Free catalog entry %s\n", ret->value);
else
xmlGenericError(xmlGenericErrorContext,
"Free catalog entry\n");
}
if (ret->name != NULL)
xmlFree(ret->name);
if (ret->value != NULL)
xmlFree(ret->value);
if (ret->URL != NULL)
xmlFree(ret->URL);
xmlFree(ret);
}
/**
* xmlFreeCatalogEntryList:
* @ret: a Catalog entry list
*
* Free the memory allocated to a full chained list of Catalog entries
*/
static void
xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) {
xmlCatalogEntryPtr next;
while (ret != NULL) {
next = ret->next;
ret = next;
}
}
* xmlFreeCatalogHashEntryList:
*
* Free the memory allocated to list of Catalog entries from the
* catalog file hash.
*/
static void
xmlFreeCatalogHashEntryList(void *payload,
const xmlChar *name ATTRIBUTE_UNUSED) {
xmlCatalogEntryPtr catal = (xmlCatalogEntryPtr) payload;
xmlCatalogEntryPtr children, next;
if (catal == NULL)
return;
children = catal->children;
while (children != NULL) {
next = children->next;
children->dealloc = 0;
children->children = NULL;
children = next;
}
catal->dealloc = 0;
}
/**
* xmlCreateNewCatalog:
* @type: type of catalog
* @prefer: the PUBLIC vs. SYSTEM current preference value
*
* create a new Catalog, this type is shared both by XML and
* SGML catalogs, but the acceptable types values differs.
*
* Returns the xmlCatalogPtr or NULL in case of error
*/
static xmlCatalogPtr
xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
xmlCatalogPtr ret;
ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog));
if (ret == NULL) {
xmlCatalogErrMemory("allocating catalog");
return(NULL);
}
memset(ret, 0, sizeof(xmlCatalog));
ret->type = type;
ret->catalNr = 0;
ret->catalMax = XML_MAX_SGML_CATA_DEPTH;
ret->prefer = prefer;
if (ret->type == XML_SGML_CATALOG_TYPE)
ret->sgml = xmlHashCreate(10);
return(ret);
}
/**
* xmlFreeCatalog:
* @catal: a Catalog
*
* Free the memory allocated to a Catalog
*/
void
xmlFreeCatalog(xmlCatalogPtr catal) {
if (catal == NULL)
return;
if (catal->xml != NULL)
xmlFreeCatalogEntryList(catal->xml);
if (catal->sgml != NULL)
xmlHashFree(catal->sgml, xmlFreeCatalogEntry);
xmlFree(catal);
}
/************************************************************************
* *
* Serializing Catalogs *
* *
************************************************************************/
#ifdef LIBXML_OUTPUT_ENABLED
/**
* xmlCatalogDumpEntry:
* @entry: the catalog entry
* @out: the file.
*
* Serialize an SGML Catalog entry
*/
static void
xmlCatalogDumpEntry(void *payload, void *data,
const xmlChar *name ATTRIBUTE_UNUSED) {
xmlCatalogEntryPtr entry = (xmlCatalogEntryPtr) payload;
FILE *out = (FILE *) data;
if ((entry == NULL) || (out == NULL))
return;
switch (entry->type) {
case SGML_CATA_ENTITY:
fprintf(out, "ENTITY "); break;
case SGML_CATA_PENTITY:
fprintf(out, "ENTITY %%"); break;
case SGML_CATA_DOCTYPE:
fprintf(out, "DOCTYPE "); break;
case SGML_CATA_LINKTYPE:
fprintf(out, "LINKTYPE "); break;
case SGML_CATA_NOTATION:
fprintf(out, "NOTATION "); break;
case SGML_CATA_PUBLIC:
fprintf(out, "PUBLIC "); break;
case SGML_CATA_SYSTEM:
fprintf(out, "SYSTEM "); break;
case SGML_CATA_DELEGATE:
fprintf(out, "DELEGATE "); break;
case SGML_CATA_BASE:
fprintf(out, "BASE "); break;
case SGML_CATA_CATALOG:
fprintf(out, "CATALOG "); break;
case SGML_CATA_DOCUMENT:
fprintf(out, "DOCUMENT "); break;
case SGML_CATA_SGMLDECL:
fprintf(out, "SGMLDECL "); break;
default:
return;
}
switch (entry->type) {
case SGML_CATA_ENTITY:
case SGML_CATA_PENTITY:
case SGML_CATA_DOCTYPE:
case SGML_CATA_LINKTYPE:
case SGML_CATA_NOTATION:
fprintf(out, "%s", (const char *) entry->name); break;
case SGML_CATA_PUBLIC:
case SGML_CATA_SYSTEM:
case SGML_CATA_SGMLDECL:
case SGML_CATA_DOCUMENT:
case SGML_CATA_CATALOG:
case SGML_CATA_BASE:
case SGML_CATA_DELEGATE:
fprintf(out, "\"%s\"", entry->name); break;
default:
break;
}
switch (entry->type) {
case SGML_CATA_ENTITY:
case SGML_CATA_PENTITY:
case SGML_CATA_DOCTYPE:
case SGML_CATA_LINKTYPE:
case SGML_CATA_NOTATION:
case SGML_CATA_PUBLIC:
case SGML_CATA_SYSTEM:
case SGML_CATA_DELEGATE:
fprintf(out, " \"%s\"", entry->value); break;
default:
break;
}
fprintf(out, "\n");
}
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
/**
* xmlDumpXMLCatalogNode:
* @catal: top catalog entry
* @catalog: pointer to the xml tree
* @doc: the containing document
* @ns: the current namespace
* @cgroup: group node for group members
*
* Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively
* for group entries
*/
static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog,
xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) {
xmlNodePtr node;
xmlCatalogEntryPtr cur;
/*
* add all the catalog entries
*/
cur = catal;
while (cur != NULL) {
if (cur->group == cgroup) {
switch (cur->type) {
case XML_CATA_REMOVED:
break;
case XML_CATA_BROKEN_CATALOG:
case XML_CATA_CATALOG:
if (cur == catal) {
cur = cur->children;
continue;
}
break;
case XML_CATA_NEXT_CATALOG:
node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL);
xmlSetProp(node, BAD_CAST "catalog", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_NONE:
break;
case XML_CATA_GROUP:
node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL);
xmlSetProp(node, BAD_CAST "id", cur->name);
if (cur->value != NULL) {
xmlNsPtr xns;
xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE);
if (xns != NULL)
xmlSetNsProp(node, xns, BAD_CAST "base",
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
switch (cur->prefer) {
case XML_CATA_PREFER_NONE:
break;
case XML_CATA_PREFER_PUBLIC:
xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public");
break;
case XML_CATA_PREFER_SYSTEM:
xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system");
break;
}
xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur);
xmlAddChild(catalog, node);
break;
case XML_CATA_PUBLIC:
node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL);
xmlSetProp(node, BAD_CAST "publicId", cur->name);
xmlSetProp(node, BAD_CAST "uri", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_SYSTEM:
node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL);
xmlSetProp(node, BAD_CAST "systemId", cur->name);
xmlSetProp(node, BAD_CAST "uri", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_REWRITE_SYSTEM:
node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL);
xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_DELEGATE_PUBLIC:
node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL);
xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name);
xmlSetProp(node, BAD_CAST "catalog", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_DELEGATE_SYSTEM:
node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL);
xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name);
xmlSetProp(node, BAD_CAST "catalog", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_URI:
node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL);
xmlSetProp(node, BAD_CAST "name", cur->name);
xmlSetProp(node, BAD_CAST "uri", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_REWRITE_URI:
node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL);
xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value);
xmlAddChild(catalog, node);
break;
case XML_CATA_DELEGATE_URI:
node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL);
xmlSetProp(node, BAD_CAST "uriStartString", cur->name);
xmlSetProp(node, BAD_CAST "catalog", cur->value);
xmlAddChild(catalog, node);
break;
case SGML_CATA_SYSTEM:
case SGML_CATA_PUBLIC:
case SGML_CATA_ENTITY:
case SGML_CATA_PENTITY:
case SGML_CATA_DOCTYPE:
case SGML_CATA_LINKTYPE:
case SGML_CATA_NOTATION:
case SGML_CATA_DELEGATE:
case SGML_CATA_BASE:
case SGML_CATA_CATALOG:
case SGML_CATA_DOCUMENT:
case SGML_CATA_SGMLDECL:
break;
}
}
cur = cur->next;
}
}
static int
xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) {
int ret;
xmlDocPtr doc;
xmlNsPtr ns;
xmlDtdPtr dtd;
xmlNodePtr catalog;
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
xmlOutputBufferPtr buf;
/*
* Rebuild a catalog
*/
doc = xmlNewDoc(NULL);
if (doc == NULL)
return(-1);
dtd = xmlNewDtd(doc, BAD_CAST "catalog",
BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN",
BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd");
xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL);
if (ns == NULL) {
xmlFreeDoc(doc);
return(-1);
}
catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL);
if (catalog == NULL) {
xmlFreeNs(ns);
xmlFreeDoc(doc);
return(-1);
}
catalog->nsDef = ns;
xmlAddChild((xmlNodePtr) doc, catalog);
xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL);
/*
* reserialize it
*/
buf = xmlOutputBufferCreateFile(out, NULL);
if (buf == NULL) {
xmlFreeDoc(doc);
return(-1);
}
ret = xmlSaveFormatFileTo(buf, doc, NULL, 1);
/*
* Free it
*/
xmlFreeDoc(doc);
return(ret);
}
#endif /* LIBXML_OUTPUT_ENABLED */
/************************************************************************
* *
* Converting SGML Catalogs to XML *
* *
************************************************************************/
/**
* xmlCatalogConvertEntry:
* @entry: the entry
* @catal: pointer to the catalog being converted
*
* Convert one entry from the catalog
*/
static void
xmlCatalogConvertEntry(void *payload, void *data,
const xmlChar *name ATTRIBUTE_UNUSED) {
xmlCatalogEntryPtr entry = (xmlCatalogEntryPtr) payload;
xmlCatalogPtr catal = (xmlCatalogPtr) data;
if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) ||
(catal->xml == NULL))
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
return;
switch (entry->type) {
case SGML_CATA_ENTITY:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_PENTITY:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_DOCTYPE:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_LINKTYPE:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_NOTATION:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_PUBLIC:
entry->type = XML_CATA_PUBLIC;
break;
case SGML_CATA_SYSTEM:
entry->type = XML_CATA_SYSTEM;
break;
case SGML_CATA_DELEGATE:
entry->type = XML_CATA_DELEGATE_PUBLIC;
break;
case SGML_CATA_CATALOG:
entry->type = XML_CATA_CATALOG;
break;
default:
xmlHashRemoveEntry(catal->sgml, entry->name, xmlFreeCatalogEntry);
return;
}
/*
* Conversion successful, remove from the SGML catalog
* and add it to the default XML one
*/
xmlHashRemoveEntry(catal->sgml, entry->name, NULL);
entry->parent = catal->xml;
entry->next = NULL;
if (catal->xml->children == NULL)
catal->xml->children = entry;
else {
xmlCatalogEntryPtr prev;
prev = catal->xml->children;
while (prev->next != NULL)
prev = prev->next;
prev->next = entry;
}
}
/**
* xmlConvertSGMLCatalog:
* @catal: the catalog
*
* Convert all the SGML catalog entries as XML ones
*
* Returns the number of entries converted if successful, -1 otherwise
*/
int
xmlConvertSGMLCatalog(xmlCatalogPtr catal) {
if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE))
return(-1);
if (xmlDebugCatalogs) {
xmlGenericError(xmlGenericErrorContext,
"Converting SGML catalog to XML\n");
}
xmlHashScan(catal->sgml, xmlCatalogConvertEntry, &catal);
return(0);
}
/************************************************************************
* *
* Helper function *
* *
************************************************************************/
/**
* xmlCatalogUnWrapURN:
* @urn: an "urn:publicid:" to unwrap
*
* Expand the URN into the equivalent Public Identifier
*
* Returns the new identifier or NULL, the string must be deallocated
* by the caller.
*/
static xmlChar *
xmlCatalogUnWrapURN(const xmlChar *urn) {
xmlChar result[2000];
unsigned int i = 0;
if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
return(NULL);
urn += sizeof(XML_URN_PUBID) - 1;
while (*urn != 0) {
if (i > sizeof(result) - 4)
break;
if (*urn == '+') {
result[i++] = ' ';
urn++;
} else if (*urn == ':') {
result[i++] = '/';
result[i++] = '/';
urn++;
} else if (*urn == ';') {
result[i++] = ':';
result[i++] = ':';
urn++;
} else if (*urn == '%') {
if ((urn[1] == '2') && (urn[2] == 'B'))
result[i++] = '+';
else if ((urn[1] == '3') && (urn[2] == 'A'))
result[i++] = ':';
else if ((urn[1] == '2') && (urn[2] == 'F'))
result[i++] = '/';
else if ((urn[1] == '3') && (urn[2] == 'B'))
result[i++] = ';';
else if ((urn[1] == '2') && (urn[2] == '7'))
result[i++] = '\'';
else if ((urn[1] == '3') && (urn[2] == 'F'))
result[i++] = '?';
else if ((urn[1] == '2') && (urn[2] == '3'))
result[i++] = '#';
else if ((urn[1] == '2') && (urn[2] == '5'))
result[i++] = '%';
else {
result[i++] = *urn;
urn++;
continue;
}
urn += 3;
} else {
result[i++] = *urn;
urn++;
}
}
result[i] = 0;
return(xmlStrdup(result));
}
/**
* xmlParseCatalogFile:
* @filename: the filename
*
* parse an XML file and build a tree. It's like xmlParseFile()
* except it bypass all catalog lookups.
*
* Returns the resulting document tree or NULL in case of error
*/
xmlDocPtr
xmlParseCatalogFile(const char *filename) {
xmlDocPtr ret;
xmlParserCtxtPtr ctxt;
char *directory = NULL;
xmlParserInputPtr inputStream;
xmlParserInputBufferPtr buf;
ctxt = xmlNewParserCtxt();
if (ctxt == NULL) {
#ifdef LIBXML_SAX1_ENABLED
if (xmlDefaultSAXHandler.error != NULL) {
xmlDefaultSAXHandler.error(NULL, "out of memory\n");
}
#endif
return(NULL);
}
buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
if (buf == NULL) {
xmlFreeParserCtxt(ctxt);
return(NULL);
}
inputStream = xmlNewInputStream(ctxt);
if (inputStream == NULL) {
xmlFreeParserCtxt(ctxt);
return(NULL);
}
Daniel Veillard
committed
inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
inputStream->buf = buf;
xmlBufResetInput(buf->buffer, inputStream);
inputPush(ctxt, inputStream);
directory = xmlParserGetDirectory(filename);
if ((ctxt->directory == NULL) && (directory != NULL))
ctxt->directory = directory;
ctxt->valid = 0;
ctxt->validate = 0;
ctxt->loadsubset = 0;
ctxt->pedantic = 0;
ctxt->dictNames = 1;
xmlParseDocument(ctxt);
if (ctxt->wellFormed)
ret = ctxt->myDoc;
else {
ret = NULL;
xmlFreeDoc(ctxt->myDoc);
ctxt->myDoc = NULL;
}
xmlFreeParserCtxt(ctxt);
return(ret);
}
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
/**
* xmlLoadFileContent:
* @filename: a file path
*
* Load a file content into memory.
*
* Returns a pointer to the 0 terminated string or NULL in case of error
*/
static xmlChar *
xmlLoadFileContent(const char *filename)
{
#ifdef HAVE_STAT
int fd;
#else
FILE *fd;
#endif
int len;
long size;
#ifdef HAVE_STAT
struct stat info;
#endif
xmlChar *content;
if (filename == NULL)
return (NULL);
#ifdef HAVE_STAT
if (stat(filename, &info) < 0)
return (NULL);
#endif
#ifdef HAVE_STAT
#else
#endif
return (NULL);
}
#ifdef HAVE_STAT
size = info.st_size;
#else
if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */
fclose(fd);
return (NULL);
}
#endif
content = (xmlChar*)xmlMallocAtomic(size + 10);
if (content == NULL) {
xmlCatalogErrMemory("allocating catalog data");
#ifdef HAVE_STAT
close(fd);
#else
fclose(fd);
#endif
return (NULL);