diff options
| author | Edwin Mons <edwin.mons@isode.com> | 2019-07-22 08:54:55 (GMT) |
|---|---|---|
| committer | Edwin Mons <edwin.mons@isode.com> | 2019-07-22 10:13:33 (GMT) |
| commit | f6fb85ba98fdd6601c4b8323c51c8367ccc4b52e (patch) | |
| tree | 16f37c7ad860a527aac7e29e4b9d7e61bf1b635f | |
| parent | f4b6bfbf4c1573e9914185e2ef170f47838ea11a (diff) | |
| download | swift-f6fb85ba98fdd6601c4b8323c51c8367ccc4b52e.zip swift-f6fb85ba98fdd6601c4b8323c51c8367ccc4b52e.tar.bz2 | |
Signal namespace declarations to ParserClients
Prior to calling handleStartElement, the ParserClient
handleNamespaceDeclaration will fire for each namespace declared on the
element.
Test-Information:
Unit tests pass on Debian 9 for both expat and libxml2
Change-Id: Ic42e83aee83edfbb2aa5c971997808eb6e133223
| -rw-r--r-- | Swiften/Parser/ExpatParser.cpp | 5 | ||||
| -rw-r--r-- | Swiften/Parser/LibXMLParser.cpp | 7 | ||||
| -rw-r--r-- | Swiften/Parser/UnitTest/XMLParserTest.cpp | 35 | ||||
| -rw-r--r-- | Swiften/Parser/XMLParserClient.cpp | 5 | ||||
| -rw-r--r-- | Swiften/Parser/XMLParserClient.h | 10 |
5 files changed, 52 insertions, 10 deletions
diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp index e4e66f2..a50949b 100644 --- a/Swiften/Parser/ExpatParser.cpp +++ b/Swiften/Parser/ExpatParser.cpp | |||
| @@ -64,6 +64,10 @@ static void handleCharacterData(void* parser, const XML_Char* data, int len) { | |||
| 64 | static void handleXMLDeclaration(void*, const XML_Char*, const XML_Char*, int) { | 64 | static void handleXMLDeclaration(void*, const XML_Char*, const XML_Char*, int) { |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static void handleNamespaceDeclaration(void* parser, const XML_Char* prefix, const XML_Char* uri) { | ||
| 68 | static_cast<XMLParser*>(parser)->getClient()->handleNamespaceDeclaration(std::string(prefix ? prefix : ""), std::string(uri ? uri : "")); | ||
| 69 | } | ||
| 70 | |||
| 67 | 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*) { | 71 | 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*) { |
| 68 | static_cast<ExpatParser*>(parser)->stopParser(); | 72 | static_cast<ExpatParser*>(parser)->stopParser(); |
| 69 | } | 73 | } |
| @@ -76,6 +80,7 @@ ExpatParser::ExpatParser(XMLParserClient* client) : XMLParser(client), p(new Pri | |||
| 76 | XML_SetCharacterDataHandler(p->parser_, handleCharacterData); | 80 | XML_SetCharacterDataHandler(p->parser_, handleCharacterData); |
| 77 | XML_SetXmlDeclHandler(p->parser_, handleXMLDeclaration); | 81 | XML_SetXmlDeclHandler(p->parser_, handleXMLDeclaration); |
| 78 | XML_SetEntityDeclHandler(p->parser_, handleEntityDeclaration); | 82 | XML_SetEntityDeclHandler(p->parser_, handleEntityDeclaration); |
| 83 | XML_SetNamespaceDeclHandler(p->parser_, handleNamespaceDeclaration, nullptr); | ||
| 79 | } | 84 | } |
| 80 | 85 | ||
| 81 | ExpatParser::~ExpatParser() { | 86 | ExpatParser::~ExpatParser() { |
diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp index c9f3a07..192f44b 100644 --- a/Swiften/Parser/LibXMLParser.cpp +++ b/Swiften/Parser/LibXMLParser.cpp | |||
| @@ -24,7 +24,7 @@ struct LibXMLParser::Private { | |||
| 24 | xmlParserCtxtPtr context_; | 24 | xmlParserCtxtPtr context_; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | static void handleStartElement(void* parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { | 27 | static void handleStartElement(void* parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int nbNamespaces, const xmlChar** namespaces, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { |
| 28 | AttributeMap attributeValues; | 28 | AttributeMap attributeValues; |
| 29 | if (nbDefaulted != 0) { | 29 | if (nbDefaulted != 0) { |
| 30 | // Just because i don't understand what this means yet :-) | 30 | // Just because i don't understand what this means yet :-) |
| @@ -42,6 +42,11 @@ static void handleStartElement(void* parser, const xmlChar* name, const xmlChar* | |||
| 42 | std::string(reinterpret_cast<const char*>(attributes[i+3]), | 42 | std::string(reinterpret_cast<const char*>(attributes[i+3]), |
| 43 | static_cast<size_t>(attributes[i+4]-attributes[i+3]))); | 43 | static_cast<size_t>(attributes[i+4]-attributes[i+3]))); |
| 44 | } | 44 | } |
| 45 | for (auto i = 0; i < nbNamespaces * 2; i += 2) { | ||
| 46 | const auto prefix = namespaces[i] ? std::string(reinterpret_cast<const char*>(namespaces[i])) : ""; | ||
| 47 | const auto uri = std::string(reinterpret_cast<const char*>(namespaces[i + 1])); | ||
| 48 | static_cast<XMLParser*>(parser)->getClient()->handleNamespaceDeclaration(prefix, uri); | ||
| 49 | } | ||
| 45 | static_cast<XMLParser*>(parser)->getClient()->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); | 50 | static_cast<XMLParser*>(parser)->getClient()->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); |
| 46 | } | 51 | } |
| 47 | 52 | ||
diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index 9e9012b..c026b4b 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <cppunit/extensions/HelperMacros.h> | 7 | #include <cppunit/extensions/HelperMacros.h> |
| 8 | #include <cppunit/extensions/TestFactoryRegistry.h> | 8 | #include <cppunit/extensions/TestFactoryRegistry.h> |
| 9 | #include <unordered_map> | ||
| 9 | #include <vector> | 10 | #include <vector> |
| 10 | 11 | ||
| 11 | #include <string> | 12 | #include <string> |
| @@ -61,6 +62,9 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 61 | CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[1].data); | 62 | CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[1].data); |
| 62 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.getEntries().size()); | 63 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.getEntries().size()); |
| 63 | CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); | 64 | CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); |
| 65 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[1].namespaces.size()); | ||
| 66 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[1].namespaces.count("")); | ||
| 67 | CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].namespaces[""]); | ||
| 64 | 68 | ||
| 65 | CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); | 69 | CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); |
| 66 | CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[2].data); | 70 | CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[2].data); |
| @@ -85,10 +89,13 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 85 | CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data); | 89 | CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data); |
| 86 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.getEntries().size()); | 90 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.getEntries().size()); |
| 87 | CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].ns); | 91 | CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].ns); |
| 92 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].namespaces.size()); | ||
| 93 | CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].namespaces[""]); | ||
| 88 | 94 | ||
| 89 | CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); | 95 | CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); |
| 90 | CPPUNIT_ASSERT_EQUAL(std::string("name"), client_.events[1].data); | 96 | CPPUNIT_ASSERT_EQUAL(std::string("name"), client_.events[1].data); |
| 91 | CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); | 97 | CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); |
| 98 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].namespaces.size()); | ||
| 92 | 99 | ||
| 93 | CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[2].type); | 100 | CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[2].type); |
| 94 | CPPUNIT_ASSERT_EQUAL(std::string("Swift"), client_.events[2].data); | 101 | CPPUNIT_ASSERT_EQUAL(std::string("Swift"), client_.events[2].data); |
| @@ -161,6 +168,8 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 161 | CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); | 168 | CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); |
| 162 | CPPUNIT_ASSERT_EQUAL(std::string("x"), client_.events[0].data); | 169 | CPPUNIT_ASSERT_EQUAL(std::string("x"), client_.events[0].data); |
| 163 | CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[0].ns); | 170 | CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[0].ns); |
| 171 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].namespaces.size()); | ||
| 172 | CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[0].namespaces["p"]); | ||
| 164 | 173 | ||
| 165 | CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); | 174 | CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); |
| 166 | CPPUNIT_ASSERT_EQUAL(std::string("y"), client_.events[1].data); | 175 | CPPUNIT_ASSERT_EQUAL(std::string("y"), client_.events[1].data); |
| @@ -262,6 +271,9 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 262 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); | 271 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); |
| 263 | CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); | 272 | CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); |
| 264 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); | 273 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); |
| 274 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); | ||
| 275 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); | ||
| 276 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]); | ||
| 265 | } | 277 | } |
| 266 | 278 | ||
| 267 | void testParse_BillionLaughs() { | 279 | void testParse_BillionLaughs() { |
| @@ -301,6 +313,7 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 301 | CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); | 313 | CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); |
| 302 | CPPUNIT_ASSERT_EQUAL(std::string("foo:bar"), client_.events[0].data); | 314 | CPPUNIT_ASSERT_EQUAL(std::string("foo:bar"), client_.events[0].data); |
| 303 | CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].ns); | 315 | CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].ns); |
| 316 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].namespaces.size()); | ||
| 304 | 317 | ||
| 305 | CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); | 318 | CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); |
| 306 | CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].data); | 319 | CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].data); |
| @@ -328,14 +341,16 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 328 | private: | 341 | private: |
| 329 | class Client : public XMLParserClient { | 342 | class Client : public XMLParserClient { |
| 330 | public: | 343 | public: |
| 331 | enum Type { StartElement, EndElement, CharacterData }; | 344 | using NamespaceMap = std::unordered_map<std::string /* prefix */, std::string /* uri */>; |
| 345 | enum Type { StartElement, EndElement, CharacterData, NamespaceDefined }; | ||
| 332 | struct Event { | 346 | struct Event { |
| 333 | Event( | 347 | Event( |
| 334 | Type type, | 348 | Type type, |
| 335 | const std::string& data, | 349 | const std::string& data, |
| 336 | const std::string& ns, | 350 | const std::string& ns, |
| 337 | const AttributeMap& attributes) | 351 | const AttributeMap& attributes, |
| 338 | : type(type), data(data), ns(ns), attributes(attributes) {} | 352 | NamespaceMap namespaces = {}) |
| 353 | : type(type), data(data), ns(ns), attributes(attributes), namespaces(std::move(namespaces)) {} | ||
| 339 | Event(Type type, const std::string& data, const std::string& ns = std::string()) | 354 | Event(Type type, const std::string& data, const std::string& ns = std::string()) |
| 340 | : type(type), data(data), ns(ns) {} | 355 | : type(type), data(data), ns(ns) {} |
| 341 | 356 | ||
| @@ -343,23 +358,29 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 343 | std::string data; | 358 | std::string data; |
| 344 | std::string ns; | 359 | std::string ns; |
| 345 | AttributeMap attributes; | 360 | AttributeMap attributes; |
| 361 | NamespaceMap namespaces; | ||
| 346 | }; | 362 | }; |
| 347 | 363 | ||
| 348 | Client() {} | 364 | Client() {} |
| 349 | 365 | ||
| 350 | virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { | 366 | void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) override { |
| 351 | events.push_back(Event(StartElement, element, ns, attributes)); | 367 | events.push_back(Event(StartElement, element, ns, attributes, std::move(namespaces_))); |
| 352 | } | 368 | } |
| 353 | 369 | ||
| 354 | virtual void handleEndElement(const std::string& element, const std::string& ns) { | 370 | void handleEndElement(const std::string& element, const std::string& ns) override { |
| 355 | events.push_back(Event(EndElement, element, ns)); | 371 | events.push_back(Event(EndElement, element, ns)); |
| 356 | } | 372 | } |
| 357 | 373 | ||
| 358 | virtual void handleCharacterData(const std::string& data) { | 374 | void handleCharacterData(const std::string& data) override { |
| 359 | events.push_back(Event(CharacterData, data)); | 375 | events.push_back(Event(CharacterData, data)); |
| 360 | } | 376 | } |
| 361 | 377 | ||
| 378 | void handleNamespaceDeclaration(const std::string& prefix, const std::string& uri) override { | ||
| 379 | namespaces_[prefix] = uri; | ||
| 380 | } | ||
| 362 | std::vector<Event> events; | 381 | std::vector<Event> events; |
| 382 | private: | ||
| 383 | NamespaceMap namespaces_; | ||
| 363 | } client_; | 384 | } client_; |
| 364 | }; | 385 | }; |
| 365 | 386 | ||
diff --git a/Swiften/Parser/XMLParserClient.cpp b/Swiften/Parser/XMLParserClient.cpp index 6dc6db6..40be4e8 100644 --- a/Swiften/Parser/XMLParserClient.cpp +++ b/Swiften/Parser/XMLParserClient.cpp | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2010 Isode Limited. | 2 | * Copyright (c) 2010-2019 Isode Limited. |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * See the COPYING file for more information. | 4 | * See the COPYING file for more information. |
| 5 | */ | 5 | */ |
| @@ -11,5 +11,8 @@ namespace Swift { | |||
| 11 | XMLParserClient::~XMLParserClient() { | 11 | XMLParserClient::~XMLParserClient() { |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | void XMLParserClient::handleNamespaceDeclaration(const std::string&, const std::string&) { | ||
| 15 | } | ||
| 16 | |||
| 14 | } | 17 | } |
| 15 | 18 | ||
diff --git a/Swiften/Parser/XMLParserClient.h b/Swiften/Parser/XMLParserClient.h index e4346f6..0682320 100644 --- a/Swiften/Parser/XMLParserClient.h +++ b/Swiften/Parser/XMLParserClient.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2010 Isode Limited. | 2 | * Copyright (c) 2010-2019 Isode Limited. |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * See the COPYING file for more information. | 4 | * See the COPYING file for more information. |
| 5 | */ | 5 | */ |
| @@ -17,5 +17,13 @@ namespace Swift { | |||
| 17 | virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) = 0; | 17 | virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) = 0; |
| 18 | virtual void handleEndElement(const std::string& element, const std::string& ns) = 0; | 18 | virtual void handleEndElement(const std::string& element, const std::string& ns) = 0; |
| 19 | virtual void handleCharacterData(const std::string& data) = 0; | 19 | virtual void handleCharacterData(const std::string& data) = 0; |
| 20 | |||
| 21 | /** | ||
| 22 | * Signal that a namespace prefix has been declared | ||
| 23 | * This callback might be called multiple times for a single element, | ||
| 24 | * and will trigger before the corresponding \ref handleStartElement | ||
| 25 | * is called. | ||
| 26 | */ | ||
| 27 | virtual void handleNamespaceDeclaration(const std::string& prefix, const std::string& uri); | ||
| 20 | }; | 28 | }; |
| 21 | } | 29 | } |
Swift