📄 catalog.c
字号:
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 xmlCatalogEntryPtrxmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename);static voidxmlParseXMLCatalogNodeList(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 xmlCatalogEntryTypexmlGetXMLCatalogEntryType(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 xmlCatalogEntryPtrxmlParseXMLCatalogOneNode(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 voidxmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer, xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup){ 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);}/** * 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 voidxmlParseXMLCatalogNodeList(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 xmlCatalogEntryPtrxmlParseXMLCatalogFile(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 intxmlFetchXMLCatalogFile(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); return(0); } if (xmlCatalogXMLFiles != NULL) { doc = (xmlCatalogEntryPtr) xmlHashLookup(xmlCatalogXMLFiles, catal->URL); if (doc != NULL) { if (xmlDebugCatalogs) xmlGenericError(xmlGenericErrorContext, "Found %s in file hash\n", catal->URL); if (catal->type == XML_CATA_CATALOG) catal->children = doc->children; else catal->children = doc; catal->dealloc = 0; xmlRMutexUnlock(xmlCatalogMutex); return(0); } if (xmlDebugCatalogs) xmlGenericError(xmlGenericErrorContext, "%s not found in file hash\n", catal->URL); } /* * Fetch and parse. Note that xmlParseXMLCatalogFile does not * use the existing catalog, there is no recursion allowed at * that level. */ doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL); if (doc == NULL) { catal->type = XML_CATA_BROKEN_CATALOG; xmlRMutexUnlock(xmlCatalogMutex); return(-1); } if (catal->type == XML_CATA_CATALOG) catal->children = doc->children; else catal->children = doc; doc->dealloc = 1; if (xmlCatalogXMLFiles == NULL) xmlCatalogXMLFiles = xmlHashCreate(10); if (xmlCatalogXMLFiles != NULL) { if (xmlDebugCatalogs) xmlGenericError(xmlGenericErrorContext, "%s added to file hash\n", catal->URL); xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -