diff options
Diffstat (limited to 'Swiften/Parser')
33 files changed, 667 insertions, 121 deletions
| diff --git a/Swiften/Parser/Attribute.h b/Swiften/Parser/Attribute.h index f54317e..07e63b4 100644 --- a/Swiften/Parser/Attribute.h +++ b/Swiften/Parser/Attribute.h @@ -14,6 +14,9 @@ namespace Swift {              Attribute(const std::string& name, const std::string& ns) : name(name), ns(ns) {              } +            Attribute(const std::string& name, const std::string& ns, const std::string& prefix) : name(name), ns(ns), prefix(prefix) { +            } +              const std::string& getName() const {                  return name;              } @@ -22,6 +25,10 @@ namespace Swift {                  return ns;              } +            const std::string& getPrefix() const { +                return prefix; +            } +              bool operator==(const Attribute& o) const {                  return o.name == name && o.ns == ns;              } @@ -29,5 +36,6 @@ namespace Swift {          private:              std::string name;              std::string ns; +            std::string prefix;      };  } diff --git a/Swiften/Parser/AttributeMap.cpp b/Swiften/Parser/AttributeMap.cpp index c112d52..7814a64 100644 --- a/Swiften/Parser/AttributeMap.cpp +++ b/Swiften/Parser/AttributeMap.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -8,19 +8,17 @@  #include <algorithm> -#include <boost/lambda/bind.hpp> -#include <boost/lambda/lambda.hpp>  #include <boost/optional.hpp>  using namespace Swift; -namespace lambda = boost::lambda;  AttributeMap::AttributeMap() {  }  std::string AttributeMap::getAttribute(const std::string& attribute, const std::string& ns) const { -    AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), -            lambda::bind(&AttributeMap::Entry::getAttribute, lambda::_1) == Attribute(attribute, ns)); +    const auto i = std::find_if(attributes.begin(), attributes.end(), [&](const Entry& entry) { +        return entry.getAttribute() == Attribute(attribute, ns); +    });      if (i == attributes.end()) {          return "";      } @@ -30,8 +28,9 @@ std::string AttributeMap::getAttribute(const std::string& attribute, const std::  }  bool AttributeMap::getBoolAttribute(const std::string& attribute, bool defaultValue) const { -    AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), -            lambda::bind(&AttributeMap::Entry::getAttribute, lambda::_1) == Attribute(attribute, "")); +    const auto i = std::find_if(attributes.begin(), attributes.end(), [&](const Entry& entry) { +        return entry.getAttribute() == Attribute(attribute, ""); +    });      if (i == attributes.end()) {          return defaultValue;      } @@ -41,8 +40,9 @@ bool AttributeMap::getBoolAttribute(const std::string& attribute, bool defaultVa  }  boost::optional<std::string> AttributeMap::getAttributeValue(const std::string& attribute) const { -    AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), -            lambda::bind(&AttributeMap::Entry::getAttribute, lambda::_1) == Attribute(attribute, "")); +    const auto i = std::find_if(attributes.begin(), attributes.end(), [&](const Entry& entry) { +        return entry.getAttribute() == Attribute(attribute, ""); +    });      if (i == attributes.end()) {          return boost::optional<std::string>();      } @@ -54,3 +54,7 @@ boost::optional<std::string> AttributeMap::getAttributeValue(const std::string&  void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& value) {      attributes.push_back(Entry(Attribute(name, ns), value));  } + +void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& prefix, const std::string& value) { +    attributes.push_back(Entry(Attribute(name, ns, prefix), value)); +} diff --git a/Swiften/Parser/AttributeMap.h b/Swiften/Parser/AttributeMap.h index 804d6aa..26d5826 100644 --- a/Swiften/Parser/AttributeMap.h +++ b/Swiften/Parser/AttributeMap.h @@ -43,6 +43,7 @@ namespace Swift {              boost::optional<std::string> getAttributeValue(const std::string&) const;              void addAttribute(const std::string& name, const std::string& ns, const std::string& value); +            void addAttribute(const std::string& name, const std::string& ns, const std::string& prefix, const std::string& value);              const std::vector<Entry>& getEntries() const {                  return attributes; diff --git a/Swiften/Parser/BOSHBodyExtractor.cpp b/Swiften/Parser/BOSHBodyExtractor.cpp index c45d338..ff56792 100644 --- a/Swiften/Parser/BOSHBodyExtractor.cpp +++ b/Swiften/Parser/BOSHBodyExtractor.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -8,8 +8,6 @@  #include <memory> -#include <boost/numeric/conversion/cast.hpp> -  #include <Swiften/Parser/XMLParser.h>  #include <Swiften/Parser/XMLParserClient.h>  #include <Swiften/Parser/XMLParserFactory.h> @@ -119,17 +117,19 @@ BOSHBodyExtractor::BOSHBodyExtractor(XMLParserFactory* parserFactory, const Byte      body = BOSHBody();      if (!endElementSeen) { +        assert(i <= j.base());          body->content = std::string(                  reinterpret_cast<const char*>(vecptr(data) + std::distance(data.begin(), i)), -                boost::numeric_cast<size_t>(std::distance(i, j.base()))); +                static_cast<size_t>(std::distance(i, j.base())));      }      // Parse the body element      BOSHBodyParserClient parserClient(this);      std::shared_ptr<XMLParser> parser(parserFactory->createXMLParser(&parserClient)); +    assert(data.begin() <= i);      if (!parser->parse(std::string(              reinterpret_cast<const char*>(vecptr(data)), -            boost::numeric_cast<size_t>(std::distance(data.begin(), i))))) { +            static_cast<size_t>(std::distance(data.begin(), i))))) {          /* TODO: This needs to be only validating the BOSH <body> element, so that XMPP parsing errors are caught at             the correct higher layer */          body = boost::optional<BOSHBody>(); diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp index 77d959c..32d4f53 100644 --- a/Swiften/Parser/ExpatParser.cpp +++ b/Swiften/Parser/ExpatParser.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -7,18 +7,46 @@  #include <Swiften/Parser/ExpatParser.h>  #include <cassert> +#include <limits>  #include <memory>  #include <string> -#include <expat.h> +#include <boost/algorithm/string.hpp> -#include <boost/numeric/conversion/cast.hpp> +#include <expat.h>  #include <Swiften/Base/String.h>  #include <Swiften/Parser/XMLParserClient.h>  #pragma clang diagnostic ignored "-Wdisabled-macro-expansion" +namespace { +struct XmlInfo { +    std::string prefix; +    std::string uri; +    std::string name; +}; + +XmlInfo splitExpatInfo(const std::string& s, char sep) { +    // name +    // uri|name +    // uri|name|prefix +    std::vector<std::string> v; +    boost::split(v, s, [sep](char c) {return c == sep; }); +    switch (v.size()) { +    case 1: +        return{ "", "", std::move(v[0]) }; +    case 2: +        return{ "", std::move(v[0]), std::move(v[1]) }; +    case 3: +        return{ std::move(v[2]), std::move(v[0]), std::move(v[1]) }; +    default: +        return{ "", "", "" }; +    } +} +} + +  namespace Swift {  static const char NAMESPACE_SEPARATOR = '\x01'; @@ -28,33 +56,24 @@ struct ExpatParser::Private {  };  static void handleStartElement(void* parser, const XML_Char* name, const XML_Char** attributes) { -    std::pair<std::string,std::string> nsTagPair = String::getSplittedAtFirst(name, NAMESPACE_SEPARATOR); -    if (nsTagPair.second == "") { -        nsTagPair.second = nsTagPair.first; -        nsTagPair.first = ""; -    } +    auto elemInfo = splitExpatInfo(name, NAMESPACE_SEPARATOR); +      AttributeMap attributeValues;      const XML_Char** currentAttribute = attributes;      while (*currentAttribute) { -        std::pair<std::string,std::string> nsAttributePair = String::getSplittedAtFirst(*currentAttribute, NAMESPACE_SEPARATOR); -        if (nsAttributePair.second == "") { -            nsAttributePair.second = nsAttributePair.first; -            nsAttributePair.first = ""; -        } -        attributeValues.addAttribute(nsAttributePair.second, nsAttributePair.first, std::string(*(currentAttribute+1))); +        auto attribInfo = splitExpatInfo(*currentAttribute, NAMESPACE_SEPARATOR); +        attributeValues.addAttribute(attribInfo.name, attribInfo.uri, attribInfo.prefix, std::string(*(currentAttribute+1)));          currentAttribute += 2;      } -    static_cast<XMLParser*>(parser)->getClient()->handleStartElement(nsTagPair.second, nsTagPair.first, attributeValues); +    auto* client = static_cast<XMLParser*>(parser)->getClient(); +    client->handleStartElementPrefix(elemInfo.prefix, elemInfo.uri, elemInfo.name, attributeValues); +    client->handleStartElement(elemInfo.name, elemInfo.uri, attributeValues);  }  static void handleEndElement(void* parser, const XML_Char* name) { -    std::pair<std::string,std::string> nsTagPair = String::getSplittedAtFirst(name, NAMESPACE_SEPARATOR); -    if (nsTagPair.second == "") { -        nsTagPair.second = nsTagPair.first; -        nsTagPair.first = ""; -    } -    static_cast<XMLParser*>(parser)->getClient()->handleEndElement(nsTagPair.second, nsTagPair.first); +    auto elemInfo = splitExpatInfo(name, NAMESPACE_SEPARATOR); +    static_cast<XMLParser*>(parser)->getClient()->handleEndElement(elemInfo.name, elemInfo.uri);  }  static void handleCharacterData(void* parser, const XML_Char* data, int len) { @@ -65,26 +84,51 @@ static void handleCharacterData(void* parser, const XML_Char* data, int len) {  static void handleXMLDeclaration(void*, const XML_Char*, const XML_Char*, int) {  } +static void handleNamespaceDeclaration(void* parser, const XML_Char* prefix, const XML_Char* uri) { +    static_cast<XMLParser*>(parser)->getClient()->handleNamespaceDeclaration(std::string(prefix ? prefix : ""), std::string(uri ? uri : "")); +} +  static void handleEntityDeclaration(void* parser, const XML_Char*, int, const XML_Char*, int, const XML_Char*, const XML_Char*, const XML_Char*, const XML_Char*) {      static_cast<ExpatParser*>(parser)->stopParser();  } +static void handleComment(void* parser, const XML_Char* /*data*/) { +    if (!static_cast<ExpatParser*>(parser)->allowsComments()) { +        static_cast<ExpatParser*>(parser)->stopParser(); +    } +} -ExpatParser::ExpatParser(XMLParserClient* client) : XMLParser(client), p(new Private()) { +static void handleProcessingInstruction(void* parser, const XML_Char* /*target*/, const XML_Char* /*data*/) { +    static_cast<ExpatParser*>(parser)->stopParser(); +} + +static void handleDoctypeDeclaration(void* parser, const XML_Char* /*doctypeName*/, const XML_Char* /*sysid*/, const XML_Char* /*pubid*/, int /*has_internal_subset*/) { +    static_cast<ExpatParser*>(parser)->stopParser(); +} + +ExpatParser::ExpatParser(XMLParserClient* client, bool allowComments) : XMLParser(client, allowComments), p(new Private()) {      p->parser_ = XML_ParserCreateNS("UTF-8", NAMESPACE_SEPARATOR); +    XML_SetReturnNSTriplet(p->parser_, true);      XML_SetUserData(p->parser_, this);      XML_SetElementHandler(p->parser_, handleStartElement, handleEndElement);      XML_SetCharacterDataHandler(p->parser_, handleCharacterData);      XML_SetXmlDeclHandler(p->parser_, handleXMLDeclaration);      XML_SetEntityDeclHandler(p->parser_, handleEntityDeclaration); +    XML_SetNamespaceDeclHandler(p->parser_, handleNamespaceDeclaration, nullptr); +    XML_SetCommentHandler(p->parser_, handleComment); +    XML_SetProcessingInstructionHandler(p->parser_, handleProcessingInstruction); +    XML_SetDoctypeDeclHandler(p->parser_, handleDoctypeDeclaration, nullptr);  }  ExpatParser::~ExpatParser() {      XML_ParserFree(p->parser_);  } -bool ExpatParser::parse(const std::string& data) { -    bool success = XML_Parse(p->parser_, data.c_str(), boost::numeric_cast<int>(data.size()), false) == XML_STATUS_OK; +bool ExpatParser::parse(const std::string& data, bool finalData) { +    if (data.size() > std::numeric_limits<int>::max()) { +        return false; +    } +    bool success = XML_Parse(p->parser_, data.c_str(), static_cast<int>(data.size()), finalData) == XML_STATUS_OK;      /*if (!success) {          std::cout << "ERROR: " << XML_ErrorString(XML_GetErrorCode(p->parser_)) << " while parsing " << data << std::endl;      }*/ diff --git a/Swiften/Parser/ExpatParser.h b/Swiften/Parser/ExpatParser.h index 12df463..34d790d 100644 --- a/Swiften/Parser/ExpatParser.h +++ b/Swiften/Parser/ExpatParser.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -16,10 +16,10 @@  namespace Swift {      class SWIFTEN_API ExpatParser : public XMLParser, public boost::noncopyable {          public: -            ExpatParser(XMLParserClient* client); +            ExpatParser(XMLParserClient* client, bool allowComments = false);              ~ExpatParser(); -            bool parse(const std::string& data); +            bool parse(const std::string& data, bool finalData = false);              void stopParser(); diff --git a/Swiften/Parser/IQParser.cpp b/Swiften/Parser/IQParser.cpp index 5cfae34..363f7ec 100644 --- a/Swiften/Parser/IQParser.cpp +++ b/Swiften/Parser/IQParser.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -32,7 +32,7 @@ void IQParser::handleStanzaAttributes(const AttributeMap& attributes) {              getStanzaGeneric()->setType(IQ::Error);          }          else { -            SWIFT_LOG(warning) << "Unknown IQ type: " << *type << std::endl; +            SWIFT_LOG(warning) << "Unknown IQ type: " << *type;              getStanzaGeneric()->setType(IQ::Get);          }      } diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp index be0a92d..32b91a1 100644 --- a/Swiften/Parser/LibXMLParser.cpp +++ b/Swiften/Parser/LibXMLParser.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -8,16 +8,21 @@  #include <cassert>  #include <cstring> +#include <limits>  #include <memory>  #include <string> -#include <boost/numeric/conversion/cast.hpp> -  #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 { @@ -25,32 +30,62 @@ struct LibXMLParser::Private {      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) { +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" << std::endl; +        SWIFT_LOG(error) << "Unexpected nbDefaulted on XML element";      }      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])); -        } +        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( -                std::string(reinterpret_cast<const char*>(attributes[i])), +                attributeName,                  attributeNS, +                attributePrefix,                  std::string(reinterpret_cast<const char*>(attributes[i+3]), -                    boost::numeric_cast<size_t>(attributes[i+4]-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);      } -    static_cast<XMLParser*>(parser)->getClient()->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); +    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*/, ... ) { @@ -65,12 +100,20 @@ static void handleError(void*, const char* /*m*/, ... ) {  static void handleWarning(void*, const char*, ... ) {  } +static void handleGenericError(void*, const char*, ... ) { +} + +static void handleStructuredError(void*, xmlErrorPtr) { +} +  bool LibXMLParser::initialized = false; -LibXMLParser::LibXMLParser(XMLParserClient* client) : XMLParser(client), p(new Private()) { +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;      } @@ -81,6 +124,10 @@ LibXMLParser::LibXMLParser(XMLParserClient* client) : XMLParser(client), p(new P      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); @@ -93,12 +140,16 @@ LibXMLParser::~LibXMLParser() {      }  } -bool LibXMLParser::parse(const std::string& data) { -    if (xmlParseChunk(p->context_, data.c_str(), boost::numeric_cast<int>(data.size()), false) == XML_ERR_OK) { +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;      } -    xmlError* error = xmlCtxtGetLastError(p->context_); -    if (error->code == XML_WAR_NS_URI || error->code == XML_WAR_NS_URI_RELATIVE) { +    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; @@ -106,4 +157,9 @@ bool LibXMLParser::parse(const std::string& data) {      return false;  } +void LibXMLParser::stopParser() { +    stopped_ = true; +    xmlStopParser(p->context_); +} +  } diff --git a/Swiften/Parser/LibXMLParser.h b/Swiften/Parser/LibXMLParser.h index 9f752ce..e21770d 100644 --- a/Swiften/Parser/LibXMLParser.h +++ b/Swiften/Parser/LibXMLParser.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -19,13 +19,16 @@ namespace Swift {       */      class LibXMLParser : public XMLParser, public boost::noncopyable {          public: -            LibXMLParser(XMLParserClient* client); +            LibXMLParser(XMLParserClient* client, bool allowComments = false);              virtual ~LibXMLParser(); -            bool parse(const std::string& data); +            bool parse(const std::string& data, bool finalData = false); + +            void stopParser();          private:              static bool initialized; +            bool stopped_ = false;              struct Private;              const std::unique_ptr<Private> p; diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp index 405c593..71bce54 100644 --- a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp +++ b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -7,6 +7,7 @@  #include <Swiften/Parser/PayloadParsers/BytestreamsParser.h>  #include <boost/lexical_cast.hpp> +#include <boost/numeric/conversion/cast.hpp>  namespace Swift { @@ -23,7 +24,9 @@ void BytestreamsParser::handleStartElement(const std::string& element, const std      else if (level == PayloadLevel) {          if (element == "streamhost") {              try { -                getPayloadInternal()->addStreamHost(Bytestreams::StreamHost(attributes.getAttribute("host"), JID(attributes.getAttribute("jid")), boost::lexical_cast<int>(attributes.getAttribute("port")))); +                getPayloadInternal()->addStreamHost(Bytestreams::StreamHost(attributes.getAttribute("host"), JID(attributes.getAttribute("jid")), boost::numeric_cast<unsigned short>(boost::lexical_cast<int>(attributes.getAttribute("port"))))); +            } +            catch (boost::numeric::bad_numeric_cast&) {              }              catch (boost::bad_lexical_cast&) {              } diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index 43c4ebb..9e56b63 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -75,6 +75,7 @@  #include <Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h>  #include <Swiften/Parser/PayloadParsers/PubSubParser.h>  #include <Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/ReferencePayloadParser.h>  #include <Swiften/Parser/PayloadParsers/ReplaceParser.h>  #include <Swiften/Parser/PayloadParsers/ResourceBindParser.h>  #include <Swiften/Parser/PayloadParsers/ResultSetParser.h> @@ -187,6 +188,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() {      factories_.push_back(std::make_shared<GenericPayloadParserFactory2<CarbonsSentParser> >("sent", "urn:xmpp:carbons:2", this));      factories_.push_back(std::make_shared<GenericPayloadParserFactory<CarbonsPrivateParser> >("private", "urn:xmpp:carbons:2"));      factories_.push_back(std::make_shared<MIXJoinParserFactory>()); +    factories_.push_back(std::make_shared<GenericPayloadParserFactory2<ReferencePayloadParser> >("reference", "urn:xmpp:reference:0", this));      for (auto& factory : factories_) {          addFactory(factory.get()); diff --git a/Swiften/Parser/PayloadParsers/IBBParser.cpp b/Swiften/Parser/PayloadParsers/IBBParser.cpp index 9b6babc..1ba44e1 100644 --- a/Swiften/Parser/PayloadParsers/IBBParser.cpp +++ b/Swiften/Parser/PayloadParsers/IBBParser.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -39,7 +39,7 @@ void IBBParser::handleStartElement(const std::string& element, const std::string                  getPayloadInternal()->setStanzaType(IBB::IQStanza);              }              try { -                getPayloadInternal()->setBlockSize(boost::lexical_cast<int>(attributes.getAttribute("block-size"))); +                getPayloadInternal()->setBlockSize(boost::lexical_cast<unsigned int>(attributes.getAttribute("block-size")));              }              catch (boost::bad_lexical_cast&) {              } diff --git a/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp b/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp index e639e20..a405e0e 100644 --- a/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp +++ b/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp @@ -5,7 +5,7 @@   */  /* - * Copyright (c) 2014-2016 Isode Limited. + * Copyright (c) 2014-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -13,6 +13,7 @@  #include <Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.h>  #include <boost/lexical_cast.hpp> +#include <boost/numeric/conversion/cast.hpp>  #include <boost/optional.hpp>  #include <Swiften/Base/Log.h> @@ -40,10 +41,10 @@ namespace Swift {                  JingleS5BTransportPayload::Candidate candidate;                  candidate.cid = attributes.getAttributeValue("cid").get_value_or(""); -                int port = -1; +                unsigned short port = 0;                  try { -                    port = boost::lexical_cast<int>(attributes.getAttributeValue("port").get_value_or("-1")); -                } catch(boost::bad_lexical_cast &) { } +                    port = boost::numeric_cast<unsigned short>(boost::lexical_cast<int>(attributes.getAttributeValue("port").get_value_or("0"))); +                } catch(...) { }                  candidate.hostPort = HostAddressPort(HostAddress::fromString(attributes.getAttributeValue("host").get_value_or("")).get_value_or(HostAddress()), port);                  candidate.jid = JID(attributes.getAttributeValue("jid").get_value_or(""));                  int priority = -1; diff --git a/Swiften/Parser/PayloadParsers/MIXUpdateSubscriptionParser.h b/Swiften/Parser/PayloadParsers/MIXUpdateSubscriptionParser.h index 9975411..47966ff 100644 --- a/Swiften/Parser/PayloadParsers/MIXUpdateSubscriptionParser.h +++ b/Swiften/Parser/PayloadParsers/MIXUpdateSubscriptionParser.h @@ -5,7 +5,7 @@   */  /* - * Copyright (c) 2017 Isode Limited. + * Copyright (c) 2017-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -24,7 +24,7 @@ namespace Swift {      class SWIFTEN_API MIXUpdateSubscriptionParser : public GenericPayloadParser<MIXUpdateSubscription> {          public:              MIXUpdateSubscriptionParser(); -            virtual ~MIXUpdateSubscriptionParser(); +            virtual ~MIXUpdateSubscriptionParser() override;              virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) override;              virtual void handleEndElement(const std::string& element, const std::string&) override; diff --git a/Swiften/Parser/PayloadParsers/ReferencePayloadParser.cpp b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.cpp new file mode 100644 index 0000000..a337a29 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/Parser/PayloadParsers/ReferencePayloadParser.h> + +#include <cassert> +#include <iostream> + +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> + +namespace Swift { + +ReferencePayloadParser::ReferencePayloadParser(PayloadParserFactoryCollection* factories) : factories_(factories) { +} + +ReferencePayload::Type ReferencePayloadParser::getTypeFromString(const std::string& typeString) const { +    if (typeString == "data") { +        return ReferencePayload::Type::Data; +    } +    else if (typeString == "mention") { +        return ReferencePayload::Type::Mention; +    } +    else if (typeString == "pubsub") { +        return ReferencePayload::Type::PubSub; +    } +    else { +        return ReferencePayload::Type::Unknown; +    } +} + +void ReferencePayloadParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { +    if (level_ == topLevel_) { +        if (element == "reference") { +            getPayloadInternal()->setType(getTypeFromString(attributes.getAttribute("type"))); +            getPayloadInternal()->setUri(attributes.getAttributeValue("uri")); +            getPayloadInternal()->setBegin(attributes.getAttributeValue("begin")); +            getPayloadInternal()->setEnd(attributes.getAttributeValue("end")); +            getPayloadInternal()->setAnchor(attributes.getAttributeValue("anchor")); +        } +    } +    else if (level_ == payloadLevel_)   { +        PayloadParserFactory* payloadParserFactory = factories_->getPayloadParserFactory(element, ns, attributes); +        if (payloadParserFactory) { +            currentPayloadParser_.reset(payloadParserFactory->createPayloadParser()); +        } +    } + +    if (level_ >= payloadLevel_ && currentPayloadParser_) { +        currentPayloadParser_->handleStartElement(element, ns, attributes); +    } + +    ++level_; +} + +void ReferencePayloadParser::handleEndElement(const std::string& element, const std::string& ns) { +    --level_; +    if (currentPayloadParser_) { +        if (level_ >= payloadLevel_) { +            currentPayloadParser_->handleEndElement(element, ns); +        } + +        if (level_ == payloadLevel_) { +            getPayloadInternal()->addPayload(currentPayloadParser_->getPayload()); +            currentPayloadParser_.reset(); +        } +    } +} + +void ReferencePayloadParser::handleCharacterData(const std::string& data) { +    if (level_ > payloadLevel_ && currentPayloadParser_) { +        currentPayloadParser_->handleCharacterData(data); +    } +} + +} diff --git a/Swiften/Parser/PayloadParsers/ReferencePayloadParser.h b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.h new file mode 100644 index 0000000..3afd181 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Elements/ReferencePayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + +    class PayloadParserFactoryCollection; + +    class SWIFTEN_API ReferencePayloadParser : public GenericPayloadParser<ReferencePayload> { +        public: + +            ReferencePayloadParser(PayloadParserFactoryCollection* factories); + +            virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes); +            virtual void handleEndElement(const std::string& element, const std::string& ns); +            virtual void handleCharacterData(const std::string& data); + +        private: + +            ReferencePayload::Type getTypeFromString(const std::string& typeString) const; +            int level_ = 0; +            const int topLevel_ = 0; +            const int payloadLevel_ = 1; +            PayloadParserFactoryCollection* factories_; +            std::shared_ptr<PayloadParser> currentPayloadParser_; +    }; +} diff --git a/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp b/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp index 502f400..7a5a1fd 100644 --- a/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp +++ b/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp @@ -5,7 +5,7 @@   */  /* - * Copyright (c) 2015-2016 Isode Limited. + * Copyright (c) 2015-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -13,6 +13,7 @@  #include <Swiften/Parser/PayloadParsers/S5BProxyRequestParser.h>  #include <boost/lexical_cast.hpp> +#include <boost/numeric/conversion/cast.hpp>  #include <boost/optional.hpp>  namespace Swift { @@ -27,15 +28,14 @@ void S5BProxyRequestParser::handleStartElement(const std::string& element, const      if (element == "streamhost") {          if (attributes.getAttributeValue("host") && attributes.getAttributeValue("jid") && attributes.getAttributeValue("port")) {              std::string host = attributes.getAttributeValue("host").get_value_or(""); -            int port = -1; +            unsigned short port = 0;              JID jid = attributes.getAttributeValue("jid").get_value_or("");              try { -                port = boost::lexical_cast<int>(attributes.getAttributeValue("port").get()); -            } catch (boost::bad_lexical_cast &) { -                port = -1; +                port = boost::numeric_cast<unsigned short>(boost::lexical_cast<int>(attributes.getAttributeValue("port").get())); +            } catch (...) {              } -            if (!host.empty() && port != -1 && jid.isValid()) { +            if (!host.empty() && port != 0 && jid.isValid()) {                  S5BProxyRequest::StreamHost streamHost;                  streamHost.host = host;                  streamHost.port = port; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h index dcdbffa..8f9e0e1 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h +++ b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h @@ -19,7 +19,7 @@ namespace Swift {      class PayloadsParserTester : public XMLParserClient {          public:              PayloadsParserTester() : level(0) { -                xmlParser = PlatformXMLParserFactory().createXMLParser(this); +                xmlParser = PlatformXMLParserFactory().createXMLParser(this, false);              }              bool parse(const std::string& data) { diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp new file mode 100644 index 0000000..ca7b280 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <gtest/gtest.h> + +#include <Swiften/Elements/Body.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Parser/PayloadParsers/ReferencePayloadParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +TEST(ReferencePayloadParserTest, testParse) { +    PayloadsParserTester parser; + +    ASSERT_TRUE(parser.parse( +        "<reference xmlns='urn:xmpp:reference:0' " +            "type='data' " +            "uri='https://www.example.com/mindBlowingImage.jpeg' " +            "begin='11' " +            "end='22' " +            "anchor='xmpp:data@localhost.example.test'>" +        "</reference>")); + +    auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload()); +    ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(payload->getType())); +    ASSERT_EQ(std::string("https://www.example.com/mindBlowingImage.jpeg"), *payload->getUri()); +    ASSERT_EQ(std::string("11"), *payload->getBegin()); +    ASSERT_EQ(std::string("22"), *payload->getEnd()); +    ASSERT_EQ(std::string("xmpp:data@localhost.example.test"), *payload->getAnchor()); +} + +TEST(ReferencePayloadParserTest, testParseNoType) { +    PayloadsParserTester parser; + +    ASSERT_TRUE(parser.parse( +        "<reference xmlns='urn:xmpp:reference:0' " +            "uri='https://www.example.com/mindBlowingImage.jpeg' " +            "begin='11' " +            "end='22' " +            "anchor='xmpp:data@localhost.example.test'>" +        "</reference>")); + +    auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload()); +    ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Unknown), static_cast<int>(payload->getType())); +    ASSERT_EQ(std::string("https://www.example.com/mindBlowingImage.jpeg"), *payload->getUri()); +    ASSERT_EQ(std::string("11"), *payload->getBegin()); +    ASSERT_EQ(std::string("22"), *payload->getEnd()); +    ASSERT_EQ(std::string("xmpp:data@localhost.example.test"), *payload->getAnchor()); +} + +TEST(ReferencePayloadParserTest, testParseEmbeddedPayloads) { +    PayloadsParserTester parser; + +    ASSERT_TRUE(parser.parse( +        "<reference xmlns='urn:xmpp:reference:0' type='data'> " +            "<error type=\"modify\">" +                "<bad-request xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>" +                "<delay xmlns='urn:xmpp:delay' from='juliet@capulet.com/balcony' stamp='2002-09-10T23:41:07Z'/>" +                "<text xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">boo</text>" +            "</error>" +        "</reference>")); + +    auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload()); +    ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(payload->getType())); +    ASSERT_FALSE(payload->getUri()); +    ASSERT_FALSE(payload->getBegin()); +    ASSERT_FALSE(payload->getEnd()); +    ASSERT_FALSE(payload->getAnchor()); +    auto childPayloadList = payload->getPayloads(); +    auto errorPayload = std::dynamic_pointer_cast<ErrorPayload>(childPayloadList[0]); +    ASSERT_TRUE(errorPayload); +    ASSERT_EQ("boo", errorPayload->getText()); +    auto delayPayload = std::dynamic_pointer_cast<Delay>(errorPayload->getPayload()); +    ASSERT_TRUE(delayPayload); +} + +TEST(ReferencePayloadParserTest, testParseEmbeddedPayloadWithText) { +    PayloadsParserTester parser; + +    ASSERT_TRUE(parser.parse( +        "<reference xmlns='urn:xmpp:reference:0' type='data'> " +            "<body>Example Text</body>" +        "</reference>")); + +    auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload()); +    auto childPayloadList = payload->getPayloads(); +    auto bodyPayload = std::dynamic_pointer_cast<Body>(childPayloadList[0]); +    ASSERT_EQ("Example Text", bodyPayload->getText()); +} + +TEST(ReferencePayloadParserTest, testParseRecursive) { +    PayloadsParserTester parser; + +    ASSERT_TRUE(parser.parse( +        "<reference xmlns='urn:xmpp:reference:0' type='data'> " +            "<reference xmlns='urn:xmpp:reference:0' type='data' uri='https://download.montague.lit/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/summit.jpg' /> " +            "<reference xmlns='urn:xmpp:reference:0' type='data' uri='xmpp:romeo@montague.lit/resource?jingle;id=9559976B-3FBF-4E7E-B457-2DAA225972BB' /> " +            "<reference xmlns='urn:xmpp:reference:0' type='data'> " +                "<reference xmlns='urn:xmpp:reference:0' type='data' uri='https://www.example.com/mindBlowingImage.jpeg' /> " +            "</reference>" +        "</reference>")); + +    auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload()); +    ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(payload->getType())); +    auto childPayloadList = payload->getPayloads(); +    auto childPayloadA = std::dynamic_pointer_cast<ReferencePayload>(childPayloadList[0]); +    auto childPayloadB = std::dynamic_pointer_cast<ReferencePayload>(childPayloadList[1]); +    auto childPayloadC = std::dynamic_pointer_cast<ReferencePayload>(childPayloadList[2]); +    ASSERT_TRUE(childPayloadA); +    ASSERT_TRUE(childPayloadB); +    ASSERT_TRUE(childPayloadC); +    ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(childPayloadA->getType())); +    ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(childPayloadB->getType())); +    ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(childPayloadC->getType())); +    ASSERT_EQ(std::string("https://download.montague.lit/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/summit.jpg"), *childPayloadA->getUri()); +    ASSERT_EQ(std::string("xmpp:romeo@montague.lit/resource?jingle;id=9559976B-3FBF-4E7E-B457-2DAA225972BB"), *childPayloadB->getUri()); +    ASSERT_FALSE(childPayloadC->getUri()); +    ASSERT_FALSE(childPayloadC->getBegin()); +    ASSERT_FALSE(childPayloadC->getEnd()); +    ASSERT_FALSE(childPayloadC->getAnchor()); +    auto grandChildPayloadList = childPayloadC->getPayloads(); +    auto grandChildPayload = std::dynamic_pointer_cast<ReferencePayload>(grandChildPayloadList[0]); +    ASSERT_TRUE(grandChildPayload); +    ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(grandChildPayload->getType())); +    ASSERT_EQ(std::string("https://www.example.com/mindBlowingImage.jpeg"), *grandChildPayload->getUri()); +    ASSERT_FALSE(grandChildPayload->getBegin()); +    ASSERT_FALSE(grandChildPayload->getEnd()); +    ASSERT_FALSE(grandChildPayload->getAnchor()); +} diff --git a/Swiften/Parser/PlatformXMLParserFactory.cpp b/Swiften/Parser/PlatformXMLParserFactory.cpp index bf66734..a424aca 100644 --- a/Swiften/Parser/PlatformXMLParserFactory.cpp +++ b/Swiften/Parser/PlatformXMLParserFactory.cpp @@ -20,11 +20,11 @@ namespace Swift {  PlatformXMLParserFactory::PlatformXMLParserFactory() {  } -std::unique_ptr<XMLParser> PlatformXMLParserFactory::createXMLParser(XMLParserClient* client) { +std::unique_ptr<XMLParser> PlatformXMLParserFactory::createXMLParser(XMLParserClient* client, bool allowComments) {  #ifdef HAVE_LIBXML -    return std::make_unique<LibXMLParser>(client); +    return std::make_unique<LibXMLParser>(client, allowComments);  #else -    return std::make_unique<ExpatParser>(client); +    return std::make_unique<ExpatParser>(client, allowComments);  #endif  } diff --git a/Swiften/Parser/PlatformXMLParserFactory.h b/Swiften/Parser/PlatformXMLParserFactory.h index fa3ca19..d72a513 100644 --- a/Swiften/Parser/PlatformXMLParserFactory.h +++ b/Swiften/Parser/PlatformXMLParserFactory.h @@ -14,6 +14,6 @@ namespace Swift {          public:              PlatformXMLParserFactory(); -            virtual std::unique_ptr<XMLParser> createXMLParser(XMLParserClient*); +            virtual std::unique_ptr<XMLParser> createXMLParser(XMLParserClient*, bool allowComments = false);      };  } diff --git a/Swiften/Parser/PresenceParser.cpp b/Swiften/Parser/PresenceParser.cpp index 0235a12..f73e9d8 100644 --- a/Swiften/Parser/PresenceParser.cpp +++ b/Swiften/Parser/PresenceParser.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -41,7 +41,7 @@ void PresenceParser::handleStanzaAttributes(const AttributeMap& attributes) {              getStanzaGeneric()->setType(Presence::Error);          }          else { -            SWIFT_LOG(error) << "Unknown Presence type: " << *type << std::endl; +            SWIFT_LOG(error) << "Unknown Presence type: " << *type;              getStanzaGeneric()->setType(Presence::Available);          }      } diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index 30c61a7..4ac5aa4 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -53,6 +53,7 @@ sources = [          "PayloadParsers/PriorityParser.cpp",          "PayloadParsers/PrivateStorageParser.cpp",          "PayloadParsers/RawXMLPayloadParser.cpp", +        "PayloadParsers/ReferencePayloadParser.cpp",          "PayloadParsers/ResourceBindParser.cpp",          "PayloadParsers/RosterItemExchangeParser.cpp",          "PayloadParsers/RosterParser.cpp", diff --git a/Swiften/Parser/StanzaAckParser.cpp b/Swiften/Parser/StanzaAckParser.cpp index de0287e..42ab181 100644 --- a/Swiften/Parser/StanzaAckParser.cpp +++ b/Swiften/Parser/StanzaAckParser.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -17,7 +17,7 @@ void StanzaAckParser::handleStartElement(const std::string&, const std::string&,      if (depth == 0) {          std::string handledStanzasString = attributes.getAttribute("h");          try { -            getElementGeneric()->setHandledStanzasCount(boost::lexical_cast<int>(handledStanzasString)); +            getElementGeneric()->setHandledStanzasCount(boost::lexical_cast<unsigned int>(handledStanzasString));          }          catch (const boost::bad_lexical_cast &) {          } diff --git a/Swiften/Parser/StreamErrorParser.cpp b/Swiften/Parser/StreamErrorParser.cpp index 64e0681..e89af58 100644 --- a/Swiften/Parser/StreamErrorParser.cpp +++ b/Swiften/Parser/StreamErrorParser.cpp @@ -48,9 +48,6 @@ void StreamErrorParser::handleEndElement(const std::string& element, const std::          else if(element == "invalid-from") {              getElementGeneric()->setType(StreamError::InvalidFrom);          } -        else if(element == "invalid-id") { -            getElementGeneric()->setType(StreamError::InvalidID); -        }          else if(element == "invalid-namespace") {              getElementGeneric()->setType(StreamError::InvalidNamespace);          } @@ -90,6 +87,9 @@ void StreamErrorParser::handleEndElement(const std::string& element, const std::          else if(element == "unsupported-encoding") {              getElementGeneric()->setType(StreamError::UnsupportedEncoding);          } +        else if(element == "unsupported-feature") { +            getElementGeneric()->setType(StreamError::UnsupportedFeature); +        }          else if(element == "unsupported-stanza-type") {              getElementGeneric()->setType(StreamError::UnsupportedStanzaType);          } diff --git a/Swiften/Parser/Tree/ParserElement.cpp b/Swiften/Parser/Tree/ParserElement.cpp index 5415945..988bc13 100644 --- a/Swiften/Parser/Tree/ParserElement.cpp +++ b/Swiften/Parser/Tree/ParserElement.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2011-2016 Isode Limited. + * Copyright (c) 2011-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -7,13 +7,8 @@  #include <Swiften/Parser/Tree/ParserElement.h> -#include <boost/lambda/bind.hpp> -#include <boost/lambda/lambda.hpp> -  #include <Swiften/Parser/Tree/NullParserElement.h> -namespace lambda = boost::lambda; -  namespace Swift {  ParserElement::ParserElement(const std::string& name, const std::string& xmlns, const AttributeMap& attributes) : name_(name), xmlns_(xmlns), attributes_(attributes) { @@ -34,8 +29,9 @@ void ParserElement::appendCharacterData(const std::string& data) {  std::vector<ParserElement::ref> ParserElement::getChildren(const std::string& name, const std::string& xmlns) const {      std::vector<ParserElement::ref> result; -    std::remove_copy_if(children_.begin(), children_.end(), std::back_inserter(result), -        lambda::bind(&ParserElement::getName, *lambda::_1) != name || lambda::bind(&ParserElement::getNamespace, *lambda::_1) != xmlns); +    std::remove_copy_if(children_.begin(), children_.end(), std::back_inserter(result), [&](const ParserElement::ref& element) { +        return (element->getName() != name) || (element->getNamespace() != xmlns); +    });      return result;  } diff --git a/Swiften/Parser/UnitTest/AttributeMapTest.cpp b/Swiften/Parser/UnitTest/AttributeMapTest.cpp index 4529eac..d9335c1 100644 --- a/Swiften/Parser/UnitTest/AttributeMapTest.cpp +++ b/Swiften/Parser/UnitTest/AttributeMapTest.cpp @@ -15,6 +15,7 @@ class AttributeMapTest : public CppUnit::TestFixture  {          CPPUNIT_TEST_SUITE(AttributeMapTest);          CPPUNIT_TEST(testGetAttribute_Namespaced); +        CPPUNIT_TEST(testGetAttribute_Namespaced_Prefix);          CPPUNIT_TEST(testGetBoolAttribute_True);          CPPUNIT_TEST(testGetBoolAttribute_1);          CPPUNIT_TEST(testGetBoolAttribute_False); @@ -34,6 +35,22 @@ class AttributeMapTest : public CppUnit::TestFixture              CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace"));          } +        void testGetAttribute_Namespaced_Prefix() { +            AttributeMap testling; +            testling.addAttribute("lang", "", "prefix", "nl"); +            testling.addAttribute("lang", "http://www.w3.org/XML/1998/namespace", "prefix", "en"); +            testling.addAttribute("lang", "", "prefix", "fr"); + +            CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace")); +            const auto& entries = testling.getEntries(); +            auto it = std::find_if(entries.begin(), entries.end(), [](const AttributeMap::Entry& e) { +                return e.getValue() == "en"; +            }); +            const bool found = it != entries.end(); +            CPPUNIT_ASSERT_EQUAL(true, found); +            CPPUNIT_ASSERT_EQUAL(std::string("prefix"), it->getAttribute().getPrefix()); +        } +          void testGetBoolAttribute_True() {              AttributeMap testling;              testling.addAttribute("foo", "", "true"); diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index b593aa7..89229c9 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp @@ -6,6 +6,7 @@  #include <cppunit/extensions/HelperMacros.h>  #include <cppunit/extensions/TestFactoryRegistry.h> +#include <unordered_map>  #include <vector>  #include <string> @@ -34,10 +35,17 @@ class XMLParserTest : public CppUnit::TestFixture {          CPPUNIT_TEST(testParse_WhitespaceInAttribute);          CPPUNIT_TEST(testParse_AttributeWithoutNamespace);          CPPUNIT_TEST(testParse_AttributeWithNamespace); +        CPPUNIT_TEST(testParse_AttributeWithNamespaceNoPrefix);          CPPUNIT_TEST(testParse_BillionLaughs);          CPPUNIT_TEST(testParse_InternalEntity);          //CPPUNIT_TEST(testParse_UndefinedPrefix);          //CPPUNIT_TEST(testParse_UndefinedAttributePrefix); +        CPPUNIT_TEST(testParse_AllowCommentsInXML); +        CPPUNIT_TEST(testParse_DisallowCommentsInXML); +        CPPUNIT_TEST(testParse_Doctype); +        CPPUNIT_TEST(testParse_ProcessingInstructions); +        CPPUNIT_TEST(testParse_ProcessingPrefixedElement); +        CPPUNIT_TEST(testParse_InvalidlyEncodedInput);          CPPUNIT_TEST_SUITE_END();      public: @@ -61,6 +69,9 @@ class XMLParserTest : public CppUnit::TestFixture {              CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[1].data);              CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.getEntries().size());              CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[1].namespaces.size()); +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[1].namespaces.count("")); +            CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].namespaces[""]);              CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type);              CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[2].data); @@ -85,10 +96,13 @@ class XMLParserTest : public CppUnit::TestFixture {              CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data);              CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.getEntries().size());              CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].ns); +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].namespaces.size()); +            CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].namespaces[""]);              CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type);              CPPUNIT_ASSERT_EQUAL(std::string("name"), client_.events[1].data);              CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].namespaces.size());              CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[2].type);              CPPUNIT_ASSERT_EQUAL(std::string("Swift"), client_.events[2].data); @@ -161,6 +175,8 @@ class XMLParserTest : public CppUnit::TestFixture {              CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type);              CPPUNIT_ASSERT_EQUAL(std::string("x"), client_.events[0].data);              CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[0].ns); +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].namespaces.size()); +            CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[0].namespaces["p"]);              CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type);              CPPUNIT_ASSERT_EQUAL(std::string("y"), client_.events[1].data); @@ -176,7 +192,7 @@ class XMLParserTest : public CppUnit::TestFixture {          }          void testParse_UnhandledXML() { -            ParserType testling(&client_); +            ParserType testling(&client_, true);              CPPUNIT_ASSERT(testling.parse("<iq><!-- Testing --></iq>")); @@ -217,6 +233,15 @@ class XMLParserTest : public CppUnit::TestFixture {              CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[1].data);          } +        void testParse_CompleteDocument() { +            ParserType testling(&client_); + +            CPPUNIT_ASSERT(!testling.parse("<iq", true)); +            CPPUNIT_ASSERT(!testling.parse("<iq>", true)); +            CPPUNIT_ASSERT(!testling.parse("<iq><child>foo</child>", true)); +            CPPUNIT_ASSERT(testling.parse("<iq><child>foo</child></iq>", true)); +        } +          void testParse_WhitespaceInAttribute() {              ParserType testling(&client_); @@ -242,6 +267,7 @@ class XMLParserTest : public CppUnit::TestFixture {              CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size());              CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName());              CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); +            CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix());          }          void testParse_AttributeWithNamespace() { @@ -253,6 +279,25 @@ class XMLParserTest : public CppUnit::TestFixture {              CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size());              CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName());              CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); +            CPPUNIT_ASSERT_EQUAL(std::string("f"), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); +            CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); +            CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]); +        } + +        void testParse_AttributeWithNamespaceNoPrefix() { +            ParserType testling(&client_); + +            CPPUNIT_ASSERT(testling.parse( +                "<query xmlns='http://swift.im' xmlns:f='http://swift.im/f' attr='3'/>")); + +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); +            CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); +            CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); +            CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); +            CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); +            CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]);          }          void testParse_BillionLaughs() { @@ -292,6 +337,7 @@ class XMLParserTest : public CppUnit::TestFixture {              CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type);              CPPUNIT_ASSERT_EQUAL(std::string("foo:bar"), client_.events[0].data);              CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].ns); +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].namespaces.size());              CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type);              CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].data); @@ -309,48 +355,136 @@ class XMLParserTest : public CppUnit::TestFixture {          void testParse_UndefinedAttributePrefix() {              ParserType testling(&client_); -            CPPUNIT_ASSERT(testling.parse( -                "<foo bar:baz='bla'/>")); +            CPPUNIT_ASSERT(testling.parse("<foo bar:baz='bla'/>"));              CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size());              CPPUNIT_ASSERT_EQUAL(std::string("bar:baz"), client_.events[0].attributes.getEntries()[0].getAttribute().getName());          } +        void testParse_AllowCommentsInXML() { +            ParserType testling(&client_, true); + +            CPPUNIT_ASSERT(testling.parse("<message><!-- Some More Comments Testing --></message>")); + +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); + +            CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); +            CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[0].data); + +            CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); +            CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[1].data); +        } + +        void testParse_DisallowCommentsInXML() { +            ParserType testling(&client_); + +            CPPUNIT_ASSERT(!testling.parse("<message><!-- Some More Comments Testing --></message>")); +        } + +        void testParse_Doctype() { +            ParserType testling(&client_); + +            CPPUNIT_ASSERT(!testling.parse("<!DOCTYPE greeting SYSTEM \"hello.dtd\">")); +        } + +        void testParse_ProcessingInstructions() { +            ParserType testling(&client_); + +            CPPUNIT_ASSERT(!testling.parse("<?xml-stylesheet type=\"text/xsl\" href=\"Sample.xsl\"?>")); +        } + +        void testParse_ProcessingPrefixedElement() { +            client_.testingStartElementPrefix = true; +            ParserType testling(&client_); + +            CPPUNIT_ASSERT(testling.parse("<prefix:message xmlns='uri' xmlns:prefix='uriPrefix'/>")); + +            CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); + +            CPPUNIT_ASSERT_EQUAL(Client::StartElementPrefix, client_.events[0].type); +            CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[0].data); +            CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[0].ns); +            CPPUNIT_ASSERT_EQUAL(std::string("prefix"), client_.events[0].prefix); + +            CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); +            CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[1].data); +            CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[1].ns); +        } + +        void testParse_InvalidlyEncodedInput() { +            ParserType testling(&client_); + +            // The following input was generated by a fuzzer, and triggered a crash in the LibXML2 parser because +            // some types of error (buffer I/O errors, for instance) will not update the error in the parser context, +            // and the code used to rely on that error always being set if parsing failed. +            // This particular input will trick the parser into believing the encoding is UTF-16LE, which eventually will lead +            // to two invalid encodings, followed by an I/O error.  The latter will end parsing without updating the +            // error in the parsing context, which used to trigger a crash. +            testling.parse(std::string("<\0?\0\x80q type='get' id='aab9a'<<query xmlns='jabber:iq:roster'/>\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9br:i><quq:private'><storage xml s='s'\x00\x10</query></iq>", 271)); +            testling.parse("<iq type='get'\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e to='ad5d8d2b25' ext='ca cs min@wonderland.t' id='aabda'><vCard xmlnr='vcard-temp'/>O/iq>"); +            testling.parse("<\xff\xff\xff\x7fype:'get' to='won\x84" "erland.lit' id='aabea'><tuery xmlns='\xd8Vtp://jabber.org/p\x88ot\x8b" "col/disco#info'/>abber.org/protocol/disco#Nnfo'/></iq>"); +        } +      private:          class Client : public XMLParserClient {              public: -                enum Type { StartElement, EndElement, CharacterData }; +                using NamespaceMap = std::unordered_map<std::string /* prefix */, std::string /* uri */>; +                enum Type { StartElement, StartElementPrefix, EndElement, CharacterData, NamespaceDefined };                  struct Event {                      Event(                              Type type,                              const std::string& data,                              const std::string& ns, -                            const AttributeMap& attributes) -                                : type(type), data(data), ns(ns), attributes(attributes) {} +                            const std::string& prefix, +                            const AttributeMap& attributes, +                            NamespaceMap namespaces) +                                : type(type), data(data), ns(ns), prefix(prefix), attributes(attributes), namespaces(std::move(namespaces)) {} +                    Event( +                            Type type, +                            const std::string& data, +                            const std::string& ns, +                            const AttributeMap& attributes, +                            NamespaceMap namespaces = {}) +                                : Event(type, data, ns, {}, attributes, std::move(namespaces)) {}                      Event(Type type, const std::string& data, const std::string& ns = std::string()) -                                : type(type), data(data), ns(ns) {} +                                : Event(type, data, ns, "", AttributeMap(), NamespaceMap()) {}                      Type type;                      std::string data;                      std::string ns; +                    std::string prefix;                      AttributeMap attributes; +                    NamespaceMap namespaces;                  };                  Client() {} -                virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { -                    events.push_back(Event(StartElement, element, ns, attributes)); +                void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) override { +                    if (testingStartElementPrefix) return; +                    events.push_back(Event(StartElement, element, ns, attributes, std::move(namespaces_)));                  } -                virtual void handleEndElement(const std::string& element, const std::string& ns) { +                void handleStartElementPrefix(const std::string& prefix, const std::string& uri, const std::string& name, const AttributeMap&) override { +                    if (!testingStartElementPrefix) return; +                    events.push_back(Event(StartElementPrefix, name, uri, prefix, AttributeMap(), NamespaceMap())); +                } + +                void handleEndElement(const std::string& element, const std::string& ns) override {                      events.push_back(Event(EndElement, element, ns));                  } -                virtual void handleCharacterData(const std::string& data) { +                void handleCharacterData(const std::string& data) override {                      events.push_back(Event(CharacterData, data));                  } +                void handleNamespaceDeclaration(const std::string& prefix, const std::string& uri) override { +                    namespaces_[prefix] = uri; +                } +                  std::vector<Event> events; +                bool testingStartElementPrefix = false; +            private: +                NamespaceMap namespaces_;          } client_;  }; diff --git a/Swiften/Parser/XMLParser.cpp b/Swiften/Parser/XMLParser.cpp index 8e92fe4..8a0799f 100644 --- a/Swiften/Parser/XMLParser.cpp +++ b/Swiften/Parser/XMLParser.cpp @@ -8,7 +8,7 @@  namespace Swift { -XMLParser::XMLParser(XMLParserClient* client) : client_(client) { +XMLParser::XMLParser(XMLParserClient* client, bool allowComments) : client_(client), allowComments_(allowComments){  }  XMLParser::~XMLParser() { diff --git a/Swiften/Parser/XMLParser.h b/Swiften/Parser/XMLParser.h index 8a73c3f..3b09d22 100644 --- a/Swiften/Parser/XMLParser.h +++ b/Swiften/Parser/XMLParser.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -15,16 +15,21 @@ namespace Swift {      class SWIFTEN_API XMLParser {          public: -            XMLParser(XMLParserClient* client); +            XMLParser(XMLParserClient* client, bool allowComments = false);              virtual ~XMLParser(); -            virtual bool parse(const std::string& data) = 0; +            virtual bool parse(const std::string& data, bool finalData = false) = 0;              XMLParserClient* getClient() const {                  return client_;              } +            bool allowsComments() const { +                return allowComments_; +            } +          private:              XMLParserClient* client_; +            const bool allowComments_ = false;      };  } diff --git a/Swiften/Parser/XMLParserClient.cpp b/Swiften/Parser/XMLParserClient.cpp index 6dc6db6..6698900 100644 --- a/Swiften/Parser/XMLParserClient.cpp +++ b/Swiften/Parser/XMLParserClient.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -11,5 +11,14 @@ namespace Swift {  XMLParserClient::~XMLParserClient() {  } +void XMLParserClient::handleStartElement(const std::string&, const std::string&, const AttributeMap&) { +} + +void XMLParserClient::handleStartElementPrefix(const std::string&, const std::string&, const std::string&, const AttributeMap&) { +} + +void XMLParserClient::handleNamespaceDeclaration(const std::string&, const std::string&) { +} +  } diff --git a/Swiften/Parser/XMLParserClient.h b/Swiften/Parser/XMLParserClient.h index e4346f6..2f0bc9e 100644 --- a/Swiften/Parser/XMLParserClient.h +++ b/Swiften/Parser/XMLParserClient.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2019 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -14,8 +14,22 @@ namespace Swift {          public:              virtual ~XMLParserClient(); -            virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) = 0; +             /** +             * Client will have to implement only one of the following methods depending on whether +             * he is interested in processing the element prefix or not. +             */ +            virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes); +            virtual void handleStartElementPrefix(const std::string& prefix, const std::string& uri, const std::string& element, const AttributeMap& attributes); +              virtual void handleEndElement(const std::string& element, const std::string& ns) = 0;              virtual void handleCharacterData(const std::string& data) = 0; + +            /** +             * Signal that a namespace prefix has been declared +             * This callback might be called multiple times for a single element, +             * and will trigger before the corresponding \ref handleStartElement +             * is called. +             */ +            virtual void handleNamespaceDeclaration(const std::string& prefix, const std::string& uri);      };  } diff --git a/Swiften/Parser/XMLParserFactory.h b/Swiften/Parser/XMLParserFactory.h index 595512b..ae3c90e 100644 --- a/Swiften/Parser/XMLParserFactory.h +++ b/Swiften/Parser/XMLParserFactory.h @@ -18,6 +18,6 @@ namespace Swift {          public:              virtual ~XMLParserFactory(); -            virtual std::unique_ptr<XMLParser> createXMLParser(XMLParserClient*) = 0; +            virtual std::unique_ptr<XMLParser> createXMLParser(XMLParserClient*, bool allowComments = false) = 0;      };  } | 
 Swift
 Swift