📄 catalog.c
字号:
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
if ((fd = open(filename, O_RDONLY)) < 0)
#else
if ((fd = fopen(filename, "rb")) == NULL)
#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 = xmlMallocAtomic(size + 10);
if (content == NULL) {
xmlCatalogErrMemory("allocating catalog data");
return (NULL);
}
#ifdef HAVE_STAT
len = read(fd, content, size);
#else
len = fread(content, 1, size, fd);
#endif
if (len < 0) {
xmlFree(content);
return (NULL);
}
#ifdef HAVE_STAT
close(fd);
#else
fclose(fd);
#endif
content[len] = 0;
return(content);
}
/**
* xmlCatalogNormalizePublic:
* @pubID: the public ID string
*
* Normalizes the Public Identifier
*
* Implements 6.2. Public Identifier Normalization
* from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html
*
* Returns the new string or NULL, the string must be deallocated
* by the caller.
*/
static xmlChar *
xmlCatalogNormalizePublic(const xmlChar *pubID)
{
int ok = 1;
int white;
const xmlChar *p;
xmlChar *ret;
xmlChar *q;
if (pubID == NULL)
return(NULL);
white = 1;
for (p = pubID;*p != 0 && ok;p++) {
if (!xmlIsBlank_ch(*p))
white = 0;
else if (*p == 0x20 && !white)
white = 1;
else
ok = 0;
}
if (ok && !white) /* is normalized */
return(NULL);
ret = xmlStrdup(pubID);
q = ret;
white = 0;
for (p = pubID;*p != 0;p++) {
if (xmlIsBlank_ch(*p)) {
if (q != ret)
white = 1;
} else {
if (white) {
*(q++) = 0x20;
white = 0;
}
*(q++) = *p;
}
}
*q = 0;
return(ret);
}
/************************************************************************
* *
* The XML Catalog parser *
* *
************************************************************************/
static xmlCatalogEntryPtr
xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);
static void
xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup);
static xmlChar *
xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
const xmlChar *sysID);
static xmlChar *
xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI);
/**
* xmlGetXMLCatalogEntryType:
* @name: the name
*
* lookup the internal type associated to an XML catalog entry name
*
* Returns the type associated with that name
*/
static xmlCatalogEntryType
xmlGetXMLCatalogEntryType(const xmlChar *name) {
xmlCatalogEntryType type = XML_CATA_NONE;
if (xmlStrEqual(name, (const xmlChar *) "system"))
type = XML_CATA_SYSTEM;
else if (xmlStrEqual(name, (const xmlChar *) "public"))
type = XML_CATA_PUBLIC;
else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem"))
type = XML_CATA_REWRITE_SYSTEM;
else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic"))
type = XML_CATA_DELEGATE_PUBLIC;
else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem"))
type = XML_CATA_DELEGATE_SYSTEM;
else if (xmlStrEqual(name, (const xmlChar *) "uri"))
type = XML_CATA_URI;
else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI"))
type = XML_CATA_REWRITE_URI;
else if (xmlStrEqual(name, (const xmlChar *) "delegateURI"))
type = XML_CATA_DELEGATE_URI;
else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog"))
type = XML_CATA_NEXT_CATALOG;
else if (xmlStrEqual(name, (const xmlChar *) "catalog"))
type = XML_CATA_CATALOG;
return(type);
}
/**
* xmlParseXMLCatalogOneNode:
* @cur: the XML node
* @type: the type of Catalog entry
* @name: the name of the node
* @attrName: the attribute holding the value
* @uriAttrName: the attribute holding the URI-Reference
* @prefer: the PUBLIC vs. SYSTEM current preference value
* @cgroup: the group which includes this node
*
* Finishes the examination of an XML tree node of a catalog and build
* a Catalog entry from it.
*
* Returns the new Catalog entry node or NULL in case of error.
*/
static xmlCatalogEntryPtr
xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
const xmlChar *name, const xmlChar *attrName,
const xmlChar *uriAttrName, xmlCatalogPrefer prefer,
xmlCatalogEntryPtr cgroup) {
int ok = 1;
xmlChar *uriValue;
xmlChar *nameValue = NULL;
xmlChar *base = NULL;
xmlChar *URL = NULL;
xmlCatalogEntryPtr ret = NULL;
if (attrName != NULL) {
nameValue = xmlGetProp(cur, attrName);
if (nameValue == NULL) {
xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
"%s entry lacks '%s'\n", name, attrName, NULL);
ok = 0;
}
}
uriValue = xmlGetProp(cur, uriAttrName);
if (uriValue == NULL) {
xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR,
"%s entry lacks '%s'\n", name, uriAttrName, NULL);
ok = 0;
}
if (!ok) {
if (nameValue != NULL)
xmlFree(nameValue);
if (uriValue != NULL)
xmlFree(uriValue);
return(NULL);
}
base = xmlNodeGetBase(cur->doc, cur);
URL = xmlBuildURI(uriValue, base);
if (URL != NULL) {
if (xmlDebugCatalogs > 1) {
if (nameValue != NULL)
xmlGenericError(xmlGenericErrorContext,
"Found %s: '%s' '%s'\n", name, nameValue, URL);
else
xmlGenericError(xmlGenericErrorContext,
"Found %s: '%s'\n", name, URL);
}
ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup);
} else {
xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN,
"%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
}
if (nameValue != NULL)
xmlFree(nameValue);
if (uriValue != NULL)
xmlFree(uriValue);
if (base != NULL)
xmlFree(base);
if (URL != NULL)
xmlFree(URL);
return(ret);
}
/**
* xmlParseXMLCatalogNode:
* @cur: the XML node
* @prefer: the PUBLIC vs. SYSTEM current preference value
* @parent: the parent Catalog entry
* @cgroup: the group which includes this node
*
* Examines an XML tree node of a catalog and build
* a Catalog entry from it adding it to its parent. The examination can
* be recursive.
*/
static void
xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer,
xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup)
{
xmlChar *uri = NULL;
xmlChar *URL = NULL;
xmlChar *base = NULL;
xmlCatalogEntryPtr entry = NULL;
if (cur == NULL)
return;
if (xmlStrEqual(cur->name, BAD_CAST "group")) {
xmlChar *prop;
xmlCatalogPrefer pref = XML_CATA_PREFER_NONE;
prop = xmlGetProp(cur, BAD_CAST "prefer");
if (prop != NULL) {
if (xmlStrEqual(prop, BAD_CAST "system")) {
prefer = XML_CATA_PREFER_SYSTEM;
} else if (xmlStrEqual(prop, BAD_CAST "public")) {
prefer = XML_CATA_PREFER_PUBLIC;
} else {
xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE,
"Invalid value for prefer: '%s'\n",
prop, NULL, NULL);
}
xmlFree(prop);
pref = prefer;
}
prop = xmlGetProp(cur, BAD_CAST "id");
base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup);
xmlFree(prop);
} else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
BAD_CAST "rewritePrefix", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
BAD_CAST "catalog", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
BAD_CAST "catalog", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
BAD_CAST "uri", BAD_CAST "name",
BAD_CAST "uri", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
BAD_CAST "rewritePrefix", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
BAD_CAST "delegateURI", BAD_CAST "uriStartString",
BAD_CAST "catalog", prefer, cgroup);
} else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
BAD_CAST "nextCatalog", NULL,
BAD_CAST "catalog", prefer, cgroup);
}
if (entry != NULL) {
if (parent != NULL) {
entry->parent = parent;
if (parent->children == NULL)
parent->children = entry;
else {
xmlCatalogEntryPtr prev;
prev = parent->children;
while (prev->next != NULL)
prev = prev->next;
prev->next = entry;
}
}
if (entry->type == XML_CATA_GROUP) {
/*
* Recurse to propagate prefer to the subtree
* (xml:base handling is automated)
*/
xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry);
}
}
if (base != NULL)
xmlFree(base);
if (uri != NULL)
xmlFree(uri);
if (URL != NULL)
xmlFree(URL);
}
/**
* xmlParseXMLCatalogNodeList:
* @cur: the XML node list of siblings
* @prefer: the PUBLIC vs. SYSTEM current preference value
* @parent: the parent Catalog entry
* @cgroup: the group which includes this list
*
* Examines a list of XML sibling nodes of a catalog and build
* a list of Catalog entry from it adding it to the parent.
* The examination will recurse to examine node subtrees.
*/
static void
xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer,
xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) {
while (cur != NULL) {
if ((cur->ns != NULL) && (cur->ns->href != NULL) &&
(xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
xmlParseXMLCatalogNode(cur, prefer, parent, cgroup);
}
cur = cur->next;
}
/* TODO: sort the list according to REWRITE lengths and prefer value */
}
/**
* xmlParseXMLCatalogFile:
* @prefer: the PUBLIC vs. SYSTEM current preference value
* @filename: the filename for the catalog
*
* Parses the catalog file to extract the XML tree and then analyze the
* tree to build a list of Catalog entries corresponding to this catalog
*
* Returns the resulting Catalog entries list
*/
static xmlCatalogEntryPtr
xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) {
xmlDocPtr doc;
xmlNodePtr cur;
xmlChar *prop;
xmlCatalogEntryPtr parent = NULL;
if (filename == NULL)
return(NULL);
doc = xmlParseCatalogFile((const char *) filename);
if (doc == NULL) {
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"Failed to parse catalog %s\n", filename);
return(NULL);
}
if (xmlDebugCatalogs)
xmlGenericError(xmlGenericErrorContext,
"%d Parsing catalog %s\n", xmlGetThreadId(), filename);
cur = xmlDocGetRootElement(doc);
if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
(cur->ns != NULL) && (cur->ns->href != NULL) &&
(xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
(const xmlChar *)filename, NULL, prefer, NULL);
if (parent == NULL) {
xmlFreeDoc(doc);
return(NULL);
}
prop = xmlGetProp(cur, BAD_CAST "prefer");
if (prop != NULL) {
if (xmlStrEqual(prop, BAD_CAST "system")) {
prefer = XML_CATA_PREFER_SYSTEM;
} else if (xmlStrEqual(prop, BAD_CAST "public")) {
prefer = XML_CATA_PREFER_PUBLIC;
} else {
xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE,
"Invalid value for prefer: '%s'\n",
prop, NULL, NULL);
}
xmlFree(prop);
}
cur = cur->children;
xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL);
} else {
xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG,
"File %s is not an XML Catalog\n",
filename, NULL, NULL);
xmlFreeDoc(doc);
return(NULL);
}
xmlFreeDoc(doc);
return(parent);
}
/**
* xmlFetchXMLCatalogFile:
* @catal: an existing but incomplete catalog entry
*
* Fetch and parse the subcatalog referenced by an entry
*
* Returns 0 in case of success, -1 otherwise
*/
static int
xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) {
xmlCatalogEntryPtr doc;
if (catal == NULL)
return(-1);
if (catal->URL == NULL)
return(-1);
if (catal->children != NULL)
return(-1);
/*
* lock the whole catalog for modification
*/
xmlRMutexLock(xmlCatalogMutex);
if (catal->children != NULL) {
/* Okay someone else did it in the meantime */
xmlRMutexUnlock(xmlCatalogMutex);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -