Signed-off-by: Jiri Denemark <jdenemar@xxxxxxxxxx> --- src/util/xml.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/util/xml.h | 19 ++++++++ 2 files changed, 159 insertions(+), 2 deletions(-) diff --git a/src/util/xml.c b/src/util/xml.c index 46ea9aa..65bc961 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -25,10 +25,19 @@ #define VIR_FROM_THIS VIR_FROM_XML -#define virXMLError(code, fmt...) \ - virReportErrorHelper(NULL, VIR_FROM_XML, code, __FILE__, \ +#define virGenericReportError(from, code, fmt...) \ + virReportErrorHelper(NULL, from, code, __FILE__, \ __FUNCTION__, __LINE__, fmt) +#define virXMLError(code, fmt...) \ + virGenericReportError(VIR_FROM_XML, code, fmt) + + +/* Internal data to be passed to SAX parser and used by error handler. */ +struct virParserData { + int domcode; +}; + /************************************************************************ * * @@ -501,3 +510,132 @@ virXPathNodeSet(const char *xpath, xmlXPathFreeObject(obj); return (ret); } + + +/** + * catchXMLError: + * + * Called from SAX on parsing errors in the XML. + */ +static void +catchXMLError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) +{ + int domcode = VIR_FROM_XML; + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + + if (ctxt) { + if (ctxt->_private) + domcode = ((struct virParserData *) ctxt->_private)->domcode; + + if (virGetLastError() == NULL && + ctxt->lastError.level == XML_ERR_FATAL && + ctxt->lastError.message != NULL) { + virGenericReportError(domcode, VIR_ERR_XML_DETAIL, + _("at line %d: %s"), + ctxt->lastError.line, + ctxt->lastError.message); + } + } +} + + +/** + * virXMLParseHelper: + * @domcode: error domain of the caller, usually VIR_FROM_THIS + * @filename: file to be parsed or NULL if string parsing is requested + * @xmlStr: XML string to be parsed in case filename is NULL + * @url: URL of XML document for string parser + * + * Parse XML document provided either as a file or a string. The function + * guarantees that the XML document contains a root element. + * + * Returns parsed XML document. + */ +xmlDocPtr +virXMLParseHelper(int domcode, + const char *filename, + const char *xmlStr, + const char *url) +{ + struct virParserData private; + xmlParserCtxtPtr pctxt; + xmlDocPtr xml = NULL; + + /* Set up a parser context so we can catch the details of XML errors. */ + pctxt = xmlNewParserCtxt(); + if (!pctxt || !pctxt->sax) + goto error; + + private.domcode = domcode; + pctxt->_private = &private; + pctxt->sax->error = catchXMLError; + + if (filename) { + xml = xmlCtxtReadFile(pctxt, filename, NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOWARNING); + } else { + xml = xmlCtxtReadDoc(pctxt, BAD_CAST xmlStr, url, NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOWARNING); + } + if (!xml) + goto error; + + if (xmlDocGetRootElement(xml) == NULL) { + virGenericReportError(domcode, VIR_ERR_INTERNAL_ERROR, + "%s", _("missing root element")); + goto error; + } + +cleanup: + xmlFreeParserCtxt(pctxt); + + return xml; + +error: + xmlFreeDoc(xml); + xml = NULL; + + if (virGetLastError() == NULL) { + virGenericReportError(domcode, VIR_ERR_XML_ERROR, + "%s", _("failed to parse xml document")); + } + goto cleanup; +} + +/** + * virXMLParseStrHelper: + * @domcode: error domain of the caller, usually VIR_FROM_THIS + * @xmlStr: XML string to be parsed in case filename is NULL + * @url: URL of XML document for string parser + * + * Parse XML document provided as a string. The function guarantees that + * the XML document contains a root element. + * + * Returns parsed XML document. + */ +xmlDocPtr +virXMLParseStrHelper(int domcode, + const char *xmlStr, + const char *url) +{ + return virXMLParseHelper(domcode, NULL, xmlStr, url); +} + +/** + * virXMLParseFileHelper: + * @domcode: error domain of the caller, usually VIR_FROM_THIS + * @filename: file to be parsed + * + * Parse XML document provided as a file. The function guarantees that + * the XML document contains a root element. + * + * Returns parsed XML document. + */ +xmlDocPtr +virXMLParseFileHelper(int domcode, + const char *filename) +{ + return virXMLParseHelper(domcode, filename, NULL, NULL); +} diff --git a/src/util/xml.h b/src/util/xml.h index 246672d..8137f90 100644 --- a/src/util/xml.h +++ b/src/util/xml.h @@ -44,4 +44,23 @@ int virXPathNodeSet(const char *xpath, char * virXMLPropString(xmlNodePtr node, const char *name); +xmlDocPtr virXMLParseHelper(int domcode, + const char *filename, + const char *xmlStr, + const char *url); +xmlDocPtr virXMLParseStrHelper(int domcode, + const char *xmlStr, + const char *url); +xmlDocPtr virXMLParseFileHelper(int domcode, + const char *filename); + +#define virXMLParse(filename, xmlStr, url) \ + virXMLParseHelper(VIR_FROM_THIS, filename, xmlStr, url) + +#define virXMLParseString(xmlStr, url) \ + virXMLParseStrHelper(VIR_FROM_THIS, xmlStr, url) + +#define virXMLParseFile(filename) \ + virXMLParseFileHelper(VIR_FROM_THIS, filename) + #endif /* __VIR_XML_H__ */ -- 1.7.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list