diff options
Diffstat (limited to 'Swiften/Parser/LibXMLParser.cpp')
| -rw-r--r-- | Swiften/Parser/LibXMLParser.cpp | 193 |
1 files changed, 126 insertions, 67 deletions
diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp index e4938e1..32b91a1 100644 --- a/Swiften/Parser/LibXMLParser.cpp +++ b/Swiften/Parser/LibXMLParser.cpp @@ -1,106 +1,165 @@ /* - * Copyright (c) 2010-2013 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010-2019 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #include <Swiften/Parser/LibXMLParser.h> -#include <iostream> -#include <boost/numeric/conversion/cast.hpp> #include <cassert> #include <cstring> -#include <libxml/parser.h> +#include <limits> +#include <memory> #include <string> +#include <libxml/parser.h> + +#include <Swiften/Base/Log.h> #include <Swiften/Parser/XMLParserClient.h> +namespace { +std::string asString(const unsigned char* s) { + return s ? std::string(reinterpret_cast<const char*>(s)) : std::string(); +} +} + namespace Swift { struct LibXMLParser::Private { - xmlSAXHandler handler_; - xmlParserCtxtPtr context_; + xmlSAXHandler handler_; + xmlParserCtxtPtr context_; }; -static void handleStartElement(void* parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { - AttributeMap attributeValues; - if (nbDefaulted != 0) { - // Just because i don't understand what this means yet :-) - std::cerr << "Unexpected nbDefaulted on XML element" << std::endl; - } - for (int i = 0; i < nbAttributes*5; i += 5) { - std::string attributeNS = ""; - if (attributes[i+2]) { - attributeNS = std::string(reinterpret_cast<const char*>(attributes[i+2])); - } - attributeValues.addAttribute( - std::string(reinterpret_cast<const char*>(attributes[i])), - attributeNS, - std::string(reinterpret_cast<const char*>(attributes[i+3]), - boost::numeric_cast<size_t>(attributes[i+4]-attributes[i+3]))); - } - static_cast<XMLParser*>(parser)->getClient()->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); +static void handleStartElement(void* parser, const xmlChar* name, const xmlChar* prefix, const xmlChar* xmlns, int nbNamespaces, const xmlChar** namespaces, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { + AttributeMap attributeValues; + if (nbDefaulted != 0) { + // Just because i don't understand what this means yet :-) + SWIFT_LOG(error) << "Unexpected nbDefaulted on XML element"; + } + for (int i = 0; i < nbAttributes*5; i += 5) { + std::string attributeName = asString(attributes[i]); + std::string attributePrefix = asString(attributes[i+1]); + std::string attributeNS = asString(attributes[i+2]); + assert(attributes[i+4] >= attributes[i+3]); + attributeValues.addAttribute( + attributeName, + attributeNS, + attributePrefix, + std::string(reinterpret_cast<const char*>(attributes[i+3]), + static_cast<size_t>(attributes[i+4]-attributes[i+3]))); + } + auto* client = static_cast<XMLParser*>(parser)->getClient(); + for (auto i = 0; i < nbNamespaces * 2; i += 2) { + const auto prefix = asString(namespaces[i]); + const auto uri = asString(namespaces[i + 1]); + client->handleNamespaceDeclaration(prefix, uri); + } + auto nameStr = asString(name); + auto xmlsnsStr = asString(xmlns); + auto prefixStr = asString(prefix); + client->handleStartElementPrefix(prefixStr, xmlsnsStr, nameStr, attributeValues); + client->handleStartElement(nameStr, xmlsnsStr, attributeValues); } static void handleEndElement(void *parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns) { - static_cast<XMLParser*>(parser)->getClient()->handleEndElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string())); + static_cast<XMLParser*>(parser)->getClient()->handleEndElement(asString(name), asString(xmlns)); } static void handleCharacterData(void* parser, const xmlChar* data, int len) { - static_cast<XMLParser*>(parser)->getClient()->handleCharacterData(std::string(reinterpret_cast<const char*>(data), boost::numeric_cast<size_t>(len))); + assert(len >= 0); + static_cast<XMLParser*>(parser)->getClient()->handleCharacterData(std::string(reinterpret_cast<const char*>(data), static_cast<size_t>(len))); +} + +static void handleComment(void* parser, const xmlChar* /*data*/) { + if (!static_cast<LibXMLParser*>(parser)->allowsComments()) { + static_cast<LibXMLParser*>(parser)->stopParser(); + } +} + +static void handleEntityDeclaration(void * parser, const xmlChar* /*name*/, int /*type*/, const xmlChar* /*publicId*/, const xmlChar* /*systemId*/, xmlChar* /*content*/) { + static_cast<LibXMLParser*>(parser)->stopParser(); +} + +static void handleProcessingInstruction(void* parser, const xmlChar* /*target*/, const xmlChar* /*data*/) { + static_cast<LibXMLParser*>(parser)->stopParser(); +} + +static void handleExternalSubset(void* parser, const xmlChar * /*name*/, const xmlChar * /*ExternalID*/, const xmlChar * /*SystemID*/) { + static_cast<LibXMLParser*>(parser)->stopParser(); } static void handleError(void*, const char* /*m*/, ... ) { - /* - va_list args; - va_start(args, m); - vfprintf(stdout, m, args); - va_end(args); - */ + /* + va_list args; + va_start(args, m); + vfprintf(stdout, m, args); + va_end(args); + */ } static void handleWarning(void*, const char*, ... ) { } -bool LibXMLParser::initialized = false; +static void handleGenericError(void*, const char*, ... ) { +} -LibXMLParser::LibXMLParser(XMLParserClient* client) : XMLParser(client), p(new Private()) { - // Initialize libXML for multithreaded applications - if (!initialized) { - xmlInitParser(); - initialized = true; - } +static void handleStructuredError(void*, xmlErrorPtr) { +} - memset(&p->handler_, 0, sizeof(p->handler_) ); - p->handler_.initialized = XML_SAX2_MAGIC; - p->handler_.startElementNs = &handleStartElement; - p->handler_.endElementNs = &handleEndElement; - p->handler_.characters = &handleCharacterData; - p->handler_.warning = &handleWarning; - p->handler_.error = &handleError; +bool LibXMLParser::initialized = false; - p->context_ = xmlCreatePushParserCtxt(&p->handler_, this, 0, 0, 0); - xmlCtxtUseOptions(p->context_, XML_PARSE_NOENT); - assert(p->context_); +LibXMLParser::LibXMLParser(XMLParserClient* client, bool allowComments) : XMLParser(client, allowComments), p(new Private()) { + // Initialize libXML for multithreaded applications + if (!initialized) { + xmlInitParser(); + xmlSetGenericErrorFunc(nullptr, handleGenericError); + xmlSetStructuredErrorFunc(nullptr, handleStructuredError); + initialized = true; + } + + memset(&p->handler_, 0, sizeof(p->handler_) ); + p->handler_.initialized = XML_SAX2_MAGIC; + p->handler_.startElementNs = &handleStartElement; + p->handler_.endElementNs = &handleEndElement; + p->handler_.characters = &handleCharacterData; + p->handler_.warning = &handleWarning; + p->handler_.error = &handleError; + p->handler_.comment = &handleComment; + p->handler_.entityDecl = &handleEntityDeclaration; + p->handler_.processingInstruction = &handleProcessingInstruction; + p->handler_.externalSubset = &handleExternalSubset; + + p->context_ = xmlCreatePushParserCtxt(&p->handler_, this, nullptr, 0, nullptr); + xmlCtxtUseOptions(p->context_, XML_PARSE_NOENT); + assert(p->context_); } LibXMLParser::~LibXMLParser() { - if (p->context_) { - xmlFreeParserCtxt(p->context_); - } -} - -bool LibXMLParser::parse(const std::string& data) { - if (xmlParseChunk(p->context_, data.c_str(), boost::numeric_cast<int>(data.size()), false) == XML_ERR_OK) { - return true; - } - xmlError* error = xmlCtxtGetLastError(p->context_); - if (error->code == XML_WAR_NS_URI || error->code == XML_WAR_NS_URI_RELATIVE) { - xmlCtxtResetLastError(p->context_); - p->context_->errNo = XML_ERR_OK; - return true; - } - return false; + if (p->context_) { + xmlFreeParserCtxt(p->context_); + } +} + +bool LibXMLParser::parse(const std::string& data, bool finalData) { + if (data.size() > std::numeric_limits<int>::max()) { + return false; + } + auto error = xmlParseChunk(p->context_, data.c_str(), static_cast<int>(data.size()), finalData); + if (error == XML_ERR_OK) { + return true; + } + if (stopped_) return false; + if (error == XML_WAR_NS_URI || error == XML_WAR_NS_URI_RELATIVE) { + xmlCtxtResetLastError(p->context_); + p->context_->errNo = XML_ERR_OK; + return true; + } + return false; +} + +void LibXMLParser::stopParser() { + stopped_ = true; + xmlStopParser(p->context_); } } |
Swift