diff options
Diffstat (limited to 'src/base/XMLHelper.cpp')
-rw-r--r-- | src/base/XMLHelper.cpp | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/src/base/XMLHelper.cpp b/src/base/XMLHelper.cpp new file mode 100644 index 0000000..6f362e8 --- /dev/null +++ b/src/base/XMLHelper.cpp @@ -0,0 +1,225 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "XMLHelper.h" +#include "Exception.h" +#include "Logger.h" + +#include <libxml/parserInternals.h> +#include <cstring> +#include <iostream> + +using namespace std; + +namespace avg { + +string getXmlChildrenAsString(const xmlDocPtr xmlDoc, const xmlNodePtr& xmlNode) +{ + string s; + xmlBufferPtr pBuffer = xmlBufferCreate(); + xmlNodeDump(pBuffer, xmlDoc, xmlNode, 0, 0); + + s = (const char *)xmlBufferContent(pBuffer); + size_t StartPos = s.find('>')+1; + size_t EndPos = s.rfind('<')-1; + if (StartPos > EndPos) { + s = ""; + } else { + s = s.substr(StartPos, EndPos-StartPos+1); + } + xmlBufferFree(pBuffer); + return s; +} + +static xmlExternalEntityLoader DefaultLoaderProc = 0; +static std::map<string, string> g_DTDMap; + +xmlParserInputPtr +DTDExternalEntityLoader(const char *pURL, const char *pID, xmlParserCtxtPtr ctxt) +{ + xmlParserInputPtr ret; + /* lookup for the fileID depending on ID */ + std::map<string, string>::iterator it = g_DTDMap.find(pURL); + + if (it != g_DTDMap.end()) { + ret = xmlNewStringInputStream(ctxt, (const xmlChar *)(it->second.c_str())); + return(ret); + } else { + ret = DefaultLoaderProc(pURL, pID, ctxt); + return(ret); + } +} + +void registerDTDEntityLoader(const string& sID, const string& sDTD) +{ + g_DTDMap[sID] = sDTD; + if (!DefaultLoaderProc) { + DefaultLoaderProc = xmlGetExternalEntityLoader(); + } + xmlSetExternalEntityLoader(DTDExternalEntityLoader); +} + + +XMLParser::XMLParser() + : m_SchemaParserCtxt(0), + m_Schema(0), + m_SchemaValidCtxt(0), + m_DTD(0), + m_DTDValidCtxt(0), + m_Doc(0) +{ + xmlPedanticParserDefault(1); + xmlSetGenericErrorFunc(this, errorOutputFunc); + xmlDoValidityCheckingDefaultValue = 0; +} + +XMLParser::~XMLParser() +{ + if (m_Schema) { + xmlSchemaFree(m_Schema); + } + if (m_SchemaParserCtxt) { + xmlSchemaFreeParserCtxt(m_SchemaParserCtxt); + } + if (m_SchemaValidCtxt) { + xmlSchemaFreeValidCtxt(m_SchemaValidCtxt); + } + if (m_DTD) { + xmlFreeDtd(m_DTD); + } + if (m_DTDValidCtxt) { + xmlFreeValidCtxt(m_DTDValidCtxt); + } + if (m_Doc) { + xmlFreeDoc(m_Doc); + } + xmlSetGenericErrorFunc(0, 0); +} + +void XMLParser::setSchema(const string& sSchema, const string& sSchemaName) +{ + AVG_ASSERT(!m_SchemaParserCtxt); + AVG_ASSERT(!m_Schema); + AVG_ASSERT(!m_SchemaValidCtxt); + AVG_ASSERT(!m_DTD); + AVG_ASSERT(!m_DTDValidCtxt); + + m_SchemaParserCtxt = xmlSchemaNewMemParserCtxt(sSchema.c_str(), sSchema.length()); + checkError(!m_SchemaParserCtxt, sSchemaName); + + m_Schema = xmlSchemaParse(m_SchemaParserCtxt); + checkError(!m_Schema, sSchemaName); + + m_SchemaValidCtxt = xmlSchemaNewValidCtxt(m_Schema); + checkError(!m_SchemaValidCtxt, sSchemaName); +} + +void XMLParser::setDTD(const std::string& sDTD, const std::string& sDTDName) +{ + AVG_ASSERT(!m_SchemaParserCtxt); + AVG_ASSERT(!m_Schema); + AVG_ASSERT(!m_SchemaValidCtxt); + AVG_ASSERT(!m_DTD); + AVG_ASSERT(!m_DTDValidCtxt); + + registerDTDEntityLoader("memory.dtd", sDTD.c_str()); + string sDTDFName = "memory.dtd"; + m_DTD = xmlParseDTD(NULL, (const xmlChar*) sDTDFName.c_str()); + checkError(!m_DTD, sDTDName); + + m_DTDValidCtxt = xmlNewValidCtxt(); + checkError(!m_DTDValidCtxt, sDTDName); + m_DTDValidCtxt->error = xmlParserValidityError; + m_DTDValidCtxt->warning = xmlParserValidityWarning; +} + +void XMLParser::parse(const string& sXML, const string& sXMLName) +{ + if (m_Doc) { + xmlFreeDoc(m_Doc); + } + m_Doc = xmlParseMemory(sXML.c_str(), int(sXML.length())); + checkError(!m_Doc, sXMLName); + + bool bOK = true; + if (m_SchemaValidCtxt) { + int err = xmlSchemaValidateDoc(m_SchemaValidCtxt, m_Doc); + AVG_ASSERT(err != -1); + bOK = (err == 0); + } + if (m_DTD) { + int err = xmlValidateDtd(m_DTDValidCtxt, m_Doc, m_DTD); + bOK = (err != 0); + } + if (!bOK) { + xmlFreeDoc(m_Doc); + m_Doc = 0; + checkError(true, sXMLName); + } +} + +xmlDocPtr XMLParser::getDoc() +{ + AVG_ASSERT(m_Doc); + return m_Doc; +} + +xmlNodePtr XMLParser::getRootNode() +{ + AVG_ASSERT(m_Doc); + return xmlDocGetRootElement(m_Doc); +} + +void XMLParser::errorOutputFunc(void * ctx, const char * msg, ...) +{ + va_list args; + va_start(args, msg); + ((XMLParser*)ctx)->internalErrorHandler(msg, args); + va_end(args); +} + +void XMLParser::internalErrorHandler(const char * msg, va_list args) +{ + char psz[1024]; + vsnprintf(psz, 1024, msg, args); + m_sError += psz; +} + +void XMLParser::checkError(bool bError, const string& sXMLName) +{ + if (bError) { + string sError = "Error parsing "+sXMLName+".\n"; + sError += m_sError; + m_sError = ""; + throw (Exception(AVG_ERR_XML_PARSE, sError)); + } +} + +void validateXml(const string& sXML, const string& sSchema, const string& sXMLName, + const string& sSchemaName) +{ + XMLParser parser; + parser.setSchema(sSchema, sSchemaName); + + parser.parse(sXML, sXMLName); +} + +} |