summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/Parser/ExpatParser.cpp19
-rw-r--r--Swiften/Parser/ExpatParser.h4
-rw-r--r--Swiften/Parser/LibXMLParser.cpp14
-rw-r--r--Swiften/Parser/UnitTest/XMLParserTest.cpp43
-rw-r--r--Swiften/Parser/XMLParser.h1
5 files changed, 66 insertions, 15 deletions
diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp
index 88be752..f091f79 100644
--- a/Swiften/Parser/ExpatParser.cpp
+++ b/Swiften/Parser/ExpatParser.cpp
@@ -10,62 +10,67 @@
#include <string>
#include <Swiften/Base/String.h>
#include "Swiften/Parser/XMLParserClient.h"
namespace Swift {
static const char NAMESPACE_SEPARATOR = '\x01';
-static void handleStartElement(void* client, const XML_Char* name, const XML_Char** attributes) {
+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 = "";
}
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[nsAttributePair.second] = std::string(*(currentAttribute+1));
currentAttribute += 2;
}
- static_cast<XMLParserClient*>(client)->handleStartElement(nsTagPair.second, nsTagPair.first, attributeValues);
+ static_cast<XMLParser*>(parser)->getClient()->handleStartElement(nsTagPair.second, nsTagPair.first, attributeValues);
}
-static void handleEndElement(void* client, const XML_Char* name) {
+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<XMLParserClient*>(client)->handleEndElement(nsTagPair.second, nsTagPair.first);
+ static_cast<XMLParser*>(parser)->getClient()->handleEndElement(nsTagPair.second, nsTagPair.first);
}
-static void handleCharacterData(void* client, const XML_Char* data, int len) {
- static_cast<XMLParserClient*>(client)->handleCharacterData(std::string(data, len));
+static void handleCharacterData(void* parser, const XML_Char* data, int len) {
+ static_cast<XMLParser*>(parser)->getClient()->handleCharacterData(std::string(data, len));
}
static void handleXMLDeclaration(void*, const XML_Char*, const XML_Char*, int) {
}
+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*) {
+ XML_StopParser(static_cast<ExpatParser*>(parser)->getParser(), static_cast<XML_Bool>(0));
+}
+
ExpatParser::ExpatParser(XMLParserClient* client) : XMLParser(client) {
parser_ = XML_ParserCreateNS("UTF-8", NAMESPACE_SEPARATOR);
- XML_SetUserData(parser_, client);
+ XML_SetUserData(parser_, this);
XML_SetElementHandler(parser_, handleStartElement, handleEndElement);
XML_SetCharacterDataHandler(parser_, handleCharacterData);
XML_SetXmlDeclHandler(parser_, handleXMLDeclaration);
+ XML_SetEntityDeclHandler(parser_, handleEntityDeclaration);
}
ExpatParser::~ExpatParser() {
XML_ParserFree(parser_);
}
bool ExpatParser::parse(const std::string& data) {
bool success = XML_Parse(parser_, data.c_str(), data.size(), false) == XML_STATUS_OK;
/*if (!success) {
diff --git a/Swiften/Parser/ExpatParser.h b/Swiften/Parser/ExpatParser.h
index f6faf17..cd981ef 100644
--- a/Swiften/Parser/ExpatParser.h
+++ b/Swiften/Parser/ExpatParser.h
@@ -14,15 +14,19 @@
namespace Swift {
class ExpatParser : public XMLParser, public boost::noncopyable {
public:
ExpatParser(XMLParserClient* client);
~ExpatParser();
bool parse(const std::string& data);
+ XML_Parser getParser() {
+ return parser_;
+ }
+
private:
XML_Parser parser_;
};
}
#endif
diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp
index 34db4ca..c94a360 100644
--- a/Swiften/Parser/LibXMLParser.cpp
+++ b/Swiften/Parser/LibXMLParser.cpp
@@ -9,32 +9,32 @@
#include <iostream>
#include <cassert>
#include <cstring>
#include <string>
#include "Swiften/Parser/XMLParserClient.h"
namespace Swift {
-static void handleStartElement(void *client, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int, const xmlChar ** attributes) {
+static void handleStartElement(void *parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int, const xmlChar ** attributes) {
AttributeMap attributeValues;
for (int i = 0; i < nbAttributes*5; i += 5) {
attributeValues[std::string(reinterpret_cast<const char*>(attributes[i]))] = std::string(reinterpret_cast<const char*>(attributes[i+3]), attributes[i+4]-attributes[i+3]);
}
- static_cast<XMLParserClient*>(client)->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues);
+ static_cast<XMLParser*>(parser)->getClient()->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues);
}
-static void handleEndElement(void *client, const xmlChar* name, const xmlChar*, const xmlChar* xmlns) {
- static_cast<XMLParserClient*>(client)->handleEndElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()));
+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 void handleCharacterData(void* client, const xmlChar* data, int len) {
- static_cast<XMLParserClient*>(client)->handleCharacterData(std::string(reinterpret_cast<const char*>(data), len));
+static void handleCharacterData(void* parser, const xmlChar* data, int len) {
+ static_cast<XMLParser*>(parser)->getClient()->handleCharacterData(std::string(reinterpret_cast<const char*>(data), len));
}
static void handleError(void*, const char* /*m*/, ... ) {
/*
va_list args;
va_start(args, m);
vfprintf(stdout, m, args);
va_end(args);
*/
@@ -48,19 +48,19 @@ static void handleWarning(void*, const char*, ... ) {
LibXMLParser::LibXMLParser(XMLParserClient* client) : XMLParser(client) {
memset(&handler_, 0, sizeof(handler_) );
handler_.initialized = XML_SAX2_MAGIC;
handler_.startElementNs = &handleStartElement;
handler_.endElementNs = &handleEndElement;
handler_.characters = &handleCharacterData;
handler_.warning = &handleWarning;
handler_.error = &handleError;
- context_ = xmlCreatePushParserCtxt(&handler_, client, 0, 0, 0);
+ context_ = xmlCreatePushParserCtxt(&handler_, this, 0, 0, 0);
assert(context_);
}
LibXMLParser::~LibXMLParser() {
if (context_) {
xmlFreeParserCtxt(context_);
}
}
diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp
index 426b7a0..2086ece 100644
--- a/Swiften/Parser/UnitTest/XMLParserTest.cpp
+++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp
@@ -19,24 +19,26 @@
using namespace Swift;
template <typename ParserType>
class XMLParserTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(XMLParserTest);
CPPUNIT_TEST(testParse_NestedElements);
CPPUNIT_TEST(testParse_ElementInNamespacedElement);
CPPUNIT_TEST(testParse_CharacterData);
+ CPPUNIT_TEST(testParse_XMLEntity);
CPPUNIT_TEST(testParse_NamespacePrefix);
CPPUNIT_TEST(testParse_UnhandledXML);
CPPUNIT_TEST(testParse_InvalidXML);
CPPUNIT_TEST(testParse_InErrorState);
CPPUNIT_TEST(testParse_Incremental);
CPPUNIT_TEST(testParse_WhitespaceInAttribute);
+ CPPUNIT_TEST(testParse_BillionLaughs);
CPPUNIT_TEST_SUITE_END();
public:
void testParse_NestedElements() {
ParserType testling(&client_);
CPPUNIT_ASSERT(testling.parse(
"<iq type=\"get\">"
"<query xmlns='jabber:iq:version'/>"
@@ -118,18 +120,38 @@ class XMLParserTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(std::string("i"), client_.events[4].data);
CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[5].type);
CPPUNIT_ASSERT_EQUAL(std::string("blo"), client_.events[5].data);
CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[6].type);
CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[6].data);
}
+ void testParse_XMLEntity() {
+ ParserType testling(&client_);
+
+ CPPUNIT_ASSERT(testling.parse("<html>&lt;&gt;</html>"));
+
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size());
+
+ CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type);
+ CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[0].data);
+
+ CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[1].type);
+ CPPUNIT_ASSERT_EQUAL(std::string("<"), client_.events[1].data);
+
+ CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[2].type);
+ CPPUNIT_ASSERT_EQUAL(std::string(">"), client_.events[2].data);
+
+ CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type);
+ CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[3].data);
+ }
+
void testParse_NamespacePrefix() {
ParserType testling(&client_);
CPPUNIT_ASSERT(testling.parse("<p:x xmlns:p='bla'><p:y/></p:x>"));
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size());
CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type);
CPPUNIT_ASSERT_EQUAL(std::string("x"), client_.events[0].data);
@@ -199,18 +221,39 @@ class XMLParserTest : public CppUnit::TestFixture {
"<presence/>"));
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), client_.events.size());
CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type);
CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data);
CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type);
CPPUNIT_ASSERT_EQUAL(std::string("presence"), client_.events[1].data);
CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type);
CPPUNIT_ASSERT_EQUAL(std::string("presence"), client_.events[2].data);
}
+
+ void testParse_BillionLaughs() {
+ ParserType testling(&client_);
+
+ CPPUNIT_ASSERT(!testling.parse(
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE lolz ["
+ " <!ENTITY lol \"lol\">"
+ " <!ENTITY lol2 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">"
+ " <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">"
+ " <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">"
+ " <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">"
+ " <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">"
+ " <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">"
+ " <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">"
+ " <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">"
+ "]>"
+ "<lolz>&lol9;</lolz>"
+ ));
+
+ }
private:
class Client : public XMLParserClient {
public:
enum Type { StartElement, EndElement, CharacterData };
struct Event {
Event(
Type type,
const std::string& data,
diff --git a/Swiften/Parser/XMLParser.h b/Swiften/Parser/XMLParser.h
index 69a6ecf..1b866e3 100644
--- a/Swiften/Parser/XMLParser.h
+++ b/Swiften/Parser/XMLParser.h
@@ -13,18 +13,17 @@ namespace Swift {
class XMLParserClient;
class XMLParser {
public:
XMLParser(XMLParserClient* client);
virtual ~XMLParser();
virtual bool parse(const std::string& data) = 0;
- protected:
XMLParserClient* getClient() const {
return client_;
}
private:
XMLParserClient* client_;
};
}