diff options
| -rw-r--r-- | Swiften/Parser/Attribute.h | 8 | ||||
| -rw-r--r-- | Swiften/Parser/AttributeMap.cpp | 4 | ||||
| -rw-r--r-- | Swiften/Parser/AttributeMap.h | 1 | ||||
| -rw-r--r-- | Swiften/Parser/ExpatParser.cpp | 57 | ||||
| -rw-r--r-- | Swiften/Parser/LibXMLParser.cpp | 33 | ||||
| -rw-r--r-- | Swiften/Parser/UnitTest/AttributeMapTest.cpp | 17 | ||||
| -rw-r--r-- | Swiften/Parser/UnitTest/XMLParserTest.cpp | 59 | ||||
| -rw-r--r-- | Swiften/Parser/XMLParserClient.cpp | 6 | ||||
| -rw-r--r-- | Swiften/Parser/XMLParserClient.h | 8 |
9 files changed, 160 insertions, 33 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 { | |||
| 14 | Attribute(const std::string& name, const std::string& ns) : name(name), ns(ns) { | 14 | Attribute(const std::string& name, const std::string& ns) : name(name), ns(ns) { |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | Attribute(const std::string& name, const std::string& ns, const std::string& prefix) : name(name), ns(ns), prefix(prefix) { | ||
| 18 | } | ||
| 19 | |||
| 17 | const std::string& getName() const { | 20 | const std::string& getName() const { |
| 18 | return name; | 21 | return name; |
| 19 | } | 22 | } |
| @@ -22,6 +25,10 @@ namespace Swift { | |||
| 22 | return ns; | 25 | return ns; |
| 23 | } | 26 | } |
| 24 | 27 | ||
| 28 | const std::string& getPrefix() const { | ||
| 29 | return prefix; | ||
| 30 | } | ||
| 31 | |||
| 25 | bool operator==(const Attribute& o) const { | 32 | bool operator==(const Attribute& o) const { |
| 26 | return o.name == name && o.ns == ns; | 33 | return o.name == name && o.ns == ns; |
| 27 | } | 34 | } |
| @@ -29,5 +36,6 @@ namespace Swift { | |||
| 29 | private: | 36 | private: |
| 30 | std::string name; | 37 | std::string name; |
| 31 | std::string ns; | 38 | std::string ns; |
| 39 | std::string prefix; | ||
| 32 | }; | 40 | }; |
| 33 | } | 41 | } |
diff --git a/Swiften/Parser/AttributeMap.cpp b/Swiften/Parser/AttributeMap.cpp index f6767de..7814a64 100644 --- a/Swiften/Parser/AttributeMap.cpp +++ b/Swiften/Parser/AttributeMap.cpp | |||
| @@ -54,3 +54,7 @@ boost::optional<std::string> AttributeMap::getAttributeValue(const std::string& | |||
| 54 | void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& value) { | 54 | void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& value) { |
| 55 | attributes.push_back(Entry(Attribute(name, ns), value)); | 55 | attributes.push_back(Entry(Attribute(name, ns), value)); |
| 56 | } | 56 | } |
| 57 | |||
| 58 | void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& prefix, const std::string& value) { | ||
| 59 | attributes.push_back(Entry(Attribute(name, ns, prefix), value)); | ||
| 60 | } | ||
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 { | |||
| 43 | boost::optional<std::string> getAttributeValue(const std::string&) const; | 43 | boost::optional<std::string> getAttributeValue(const std::string&) const; |
| 44 | 44 | ||
| 45 | void addAttribute(const std::string& name, const std::string& ns, const std::string& value); | 45 | void addAttribute(const std::string& name, const std::string& ns, const std::string& value); |
| 46 | void addAttribute(const std::string& name, const std::string& ns, const std::string& prefix, const std::string& value); | ||
| 46 | 47 | ||
| 47 | const std::vector<Entry>& getEntries() const { | 48 | const std::vector<Entry>& getEntries() const { |
| 48 | return attributes; | 49 | return attributes; |
diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp index 640d561..6c3845a 100644 --- a/Swiften/Parser/ExpatParser.cpp +++ b/Swiften/Parser/ExpatParser.cpp | |||
| @@ -11,6 +11,8 @@ | |||
| 11 | #include <memory> | 11 | #include <memory> |
| 12 | #include <string> | 12 | #include <string> |
| 13 | 13 | ||
| 14 | #include <boost/algorithm/string.hpp> | ||
| 15 | |||
| 14 | #include <expat.h> | 16 | #include <expat.h> |
| 15 | 17 | ||
| 16 | #include <Swiften/Base/String.h> | 18 | #include <Swiften/Base/String.h> |
| @@ -18,6 +20,33 @@ | |||
| 18 | 20 | ||
| 19 | #pragma clang diagnostic ignored "-Wdisabled-macro-expansion" | 21 | #pragma clang diagnostic ignored "-Wdisabled-macro-expansion" |
| 20 | 22 | ||
| 23 | namespace { | ||
| 24 | struct XmlInfo { | ||
| 25 | std::string prefix; | ||
| 26 | std::string uri; | ||
| 27 | std::string name; | ||
| 28 | }; | ||
| 29 | |||
| 30 | XmlInfo splitExpatInfo(const std::string& s, char sep) { | ||
| 31 | // name | ||
| 32 | // uri|name | ||
| 33 | // uri|name|prefix | ||
| 34 | std::vector<std::string> v; | ||
| 35 | boost::split(v, s, [sep](char c) {return c == sep; }); | ||
| 36 | switch (v.size()) { | ||
| 37 | case 1: | ||
| 38 | return{ "", "", std::move(v[0]) }; | ||
| 39 | case 2: | ||
| 40 | return{ "", std::move(v[0]), std::move(v[1]) }; | ||
| 41 | case 3: | ||
| 42 | return{ std::move(v[2]), std::move(v[0]), std::move(v[1]) }; | ||
| 43 | default: | ||
| 44 | return{ "", "", "" }; | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | |||
| 21 | namespace Swift { | 50 | namespace Swift { |
| 22 | 51 | ||
| 23 | static const char NAMESPACE_SEPARATOR = '\x01'; | 52 | static const char NAMESPACE_SEPARATOR = '\x01'; |
| @@ -27,33 +56,24 @@ struct ExpatParser::Private { | |||
| 27 | }; | 56 | }; |
| 28 | 57 | ||
| 29 | static void handleStartElement(void* parser, const XML_Char* name, const XML_Char** attributes) { | 58 | static void handleStartElement(void* parser, const XML_Char* name, const XML_Char** attributes) { |
| 30 | std::pair<std::string,std::string> nsTagPair = String::getSplittedAtFirst(name, NAMESPACE_SEPARATOR); | 59 | auto elemInfo = splitExpatInfo(name, NAMESPACE_SEPARATOR); |
| 31 | if (nsTagPair.second == "") { | 60 | |
| 32 | nsTagPair.second = nsTagPair.first; | ||
| 33 | nsTagPair.first = ""; | ||
| 34 | } | ||
| 35 | AttributeMap attributeValues; | 61 | AttributeMap attributeValues; |
| 36 | const XML_Char** currentAttribute = attributes; | 62 | const XML_Char** currentAttribute = attributes; |
| 37 | while (*currentAttribute) { | 63 | while (*currentAttribute) { |
| 38 | std::pair<std::string,std::string> nsAttributePair = String::getSplittedAtFirst(*currentAttribute, NAMESPACE_SEPARATOR); | 64 | auto attribInfo = splitExpatInfo(*currentAttribute, NAMESPACE_SEPARATOR); |
| 39 | if (nsAttributePair.second == "") { | 65 | attributeValues.addAttribute(attribInfo.name, attribInfo.uri, attribInfo.prefix, std::string(*(currentAttribute+1))); |
| 40 | nsAttributePair.second = nsAttributePair.first; | ||
| 41 | nsAttributePair.first = ""; | ||
| 42 | } | ||
| 43 | attributeValues.addAttribute(nsAttributePair.second, nsAttributePair.first, std::string(*(currentAttribute+1))); | ||
| 44 | currentAttribute += 2; | 66 | currentAttribute += 2; |
| 45 | } | 67 | } |
| 46 | 68 | ||
| 47 | static_cast<XMLParser*>(parser)->getClient()->handleStartElement(nsTagPair.second, nsTagPair.first, attributeValues); | 69 | auto* client = static_cast<XMLParser*>(parser)->getClient(); |
| 70 | client->handleStartElementPrefix(elemInfo.prefix, elemInfo.uri, elemInfo.name, elemInfo.name, elemInfo.uri, attributeValues); | ||
| 71 | client->handleStartElement(elemInfo.name, elemInfo.uri, attributeValues); | ||
| 48 | } | 72 | } |
| 49 | 73 | ||
| 50 | static void handleEndElement(void* parser, const XML_Char* name) { | 74 | static void handleEndElement(void* parser, const XML_Char* name) { |
| 51 | std::pair<std::string,std::string> nsTagPair = String::getSplittedAtFirst(name, NAMESPACE_SEPARATOR); | 75 | auto elemInfo = splitExpatInfo(name, NAMESPACE_SEPARATOR); |
| 52 | if (nsTagPair.second == "") { | 76 | static_cast<XMLParser*>(parser)->getClient()->handleEndElement(elemInfo.name, elemInfo.uri); |
| 53 | nsTagPair.second = nsTagPair.first; | ||
| 54 | nsTagPair.first = ""; | ||
| 55 | } | ||
| 56 | static_cast<XMLParser*>(parser)->getClient()->handleEndElement(nsTagPair.second, nsTagPair.first); | ||
| 57 | } | 77 | } |
| 58 | 78 | ||
| 59 | static void handleCharacterData(void* parser, const XML_Char* data, int len) { | 79 | static void handleCharacterData(void* parser, const XML_Char* data, int len) { |
| @@ -88,6 +108,7 @@ static void handleDoctypeDeclaration(void* parser, const XML_Char* /*doctypeName | |||
| 88 | 108 | ||
| 89 | ExpatParser::ExpatParser(XMLParserClient* client, bool allowComments) : XMLParser(client, allowComments), p(new Private()) { | 109 | ExpatParser::ExpatParser(XMLParserClient* client, bool allowComments) : XMLParser(client, allowComments), p(new Private()) { |
| 90 | p->parser_ = XML_ParserCreateNS("UTF-8", NAMESPACE_SEPARATOR); | 110 | p->parser_ = XML_ParserCreateNS("UTF-8", NAMESPACE_SEPARATOR); |
| 111 | XML_SetReturnNSTriplet(p->parser_, true); | ||
| 91 | XML_SetUserData(p->parser_, this); | 112 | XML_SetUserData(p->parser_, this); |
| 92 | XML_SetElementHandler(p->parser_, handleStartElement, handleEndElement); | 113 | XML_SetElementHandler(p->parser_, handleStartElement, handleEndElement); |
| 93 | XML_SetCharacterDataHandler(p->parser_, handleCharacterData); | 114 | XML_SetCharacterDataHandler(p->parser_, handleCharacterData); |
diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp index 4e02059..71515a7 100644 --- a/Swiften/Parser/LibXMLParser.cpp +++ b/Swiften/Parser/LibXMLParser.cpp | |||
| @@ -17,6 +17,12 @@ | |||
| 17 | #include <Swiften/Base/Log.h> | 17 | #include <Swiften/Base/Log.h> |
| 18 | #include <Swiften/Parser/XMLParserClient.h> | 18 | #include <Swiften/Parser/XMLParserClient.h> |
| 19 | 19 | ||
| 20 | namespace { | ||
| 21 | std::string asString(const unsigned char* s) { | ||
| 22 | return s ? std::string(reinterpret_cast<const char*>(s)) : std::string(); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 20 | namespace Swift { | 26 | namespace Swift { |
| 21 | 27 | ||
| 22 | struct LibXMLParser::Private { | 28 | struct LibXMLParser::Private { |
| @@ -24,34 +30,39 @@ struct LibXMLParser::Private { | |||
| 24 | xmlParserCtxtPtr context_; | 30 | xmlParserCtxtPtr context_; |
| 25 | }; | 31 | }; |
| 26 | 32 | ||
| 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) { | 33 | 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) { |
| 28 | AttributeMap attributeValues; | 34 | AttributeMap attributeValues; |
| 29 | if (nbDefaulted != 0) { | 35 | if (nbDefaulted != 0) { |
| 30 | // Just because i don't understand what this means yet :-) | 36 | // Just because i don't understand what this means yet :-) |
| 31 | SWIFT_LOG(error) << "Unexpected nbDefaulted on XML element" << std::endl; | 37 | SWIFT_LOG(error) << "Unexpected nbDefaulted on XML element" << std::endl; |
| 32 | } | 38 | } |
| 33 | for (int i = 0; i < nbAttributes*5; i += 5) { | 39 | for (int i = 0; i < nbAttributes*5; i += 5) { |
| 34 | std::string attributeNS = ""; | 40 | std::string attributeName = asString(attributes[i]); |
| 35 | if (attributes[i+2]) { | 41 | std::string attributePrefix = asString(attributes[i+1]); |
| 36 | attributeNS = std::string(reinterpret_cast<const char*>(attributes[i+2])); | 42 | std::string attributeNS = asString(attributes[i+2]); |
| 37 | } | ||
| 38 | assert(attributes[i+4] >= attributes[i+3]); | 43 | assert(attributes[i+4] >= attributes[i+3]); |
| 39 | attributeValues.addAttribute( | 44 | attributeValues.addAttribute( |
| 40 | std::string(reinterpret_cast<const char*>(attributes[i])), | 45 | attributeName, |
| 41 | attributeNS, | 46 | attributeNS, |
| 47 | attributePrefix, | ||
| 42 | std::string(reinterpret_cast<const char*>(attributes[i+3]), | 48 | std::string(reinterpret_cast<const char*>(attributes[i+3]), |
| 43 | static_cast<size_t>(attributes[i+4]-attributes[i+3]))); | 49 | static_cast<size_t>(attributes[i+4]-attributes[i+3]))); |
| 44 | } | 50 | } |
| 51 | auto* client = static_cast<XMLParser*>(parser)->getClient(); | ||
| 45 | for (auto i = 0; i < nbNamespaces * 2; i += 2) { | 52 | for (auto i = 0; i < nbNamespaces * 2; i += 2) { |
| 46 | const auto prefix = namespaces[i] ? std::string(reinterpret_cast<const char*>(namespaces[i])) : ""; | 53 | const auto prefix = asString(namespaces[i]); |
| 47 | const auto uri = std::string(reinterpret_cast<const char*>(namespaces[i + 1])); | 54 | const auto uri = asString(namespaces[i + 1]); |
| 48 | static_cast<XMLParser*>(parser)->getClient()->handleNamespaceDeclaration(prefix, uri); | 55 | client->handleNamespaceDeclaration(prefix, uri); |
| 49 | } | 56 | } |
| 50 | static_cast<XMLParser*>(parser)->getClient()->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); | 57 | auto nameStr = asString(name); |
| 58 | auto xmlsnsStr = asString(xmlns); | ||
| 59 | auto prefixStr = asString(prefix); | ||
| 60 | client->handleStartElementPrefix(prefixStr, xmlsnsStr, nameStr, nameStr, xmlsnsStr, attributeValues); | ||
| 61 | client->handleStartElement(nameStr, xmlsnsStr, attributeValues); | ||
| 51 | } | 62 | } |
| 52 | 63 | ||
| 53 | static void handleEndElement(void *parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns) { | 64 | static void handleEndElement(void *parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns) { |
| 54 | static_cast<XMLParser*>(parser)->getClient()->handleEndElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string())); | 65 | static_cast<XMLParser*>(parser)->getClient()->handleEndElement(asString(name), asString(xmlns)); |
| 55 | } | 66 | } |
| 56 | 67 | ||
| 57 | static void handleCharacterData(void* parser, const xmlChar* data, int len) { | 68 | static void handleCharacterData(void* parser, const xmlChar* data, int len) { |
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 | |||
| 15 | { | 15 | { |
| 16 | CPPUNIT_TEST_SUITE(AttributeMapTest); | 16 | CPPUNIT_TEST_SUITE(AttributeMapTest); |
| 17 | CPPUNIT_TEST(testGetAttribute_Namespaced); | 17 | CPPUNIT_TEST(testGetAttribute_Namespaced); |
| 18 | CPPUNIT_TEST(testGetAttribute_Namespaced_Prefix); | ||
| 18 | CPPUNIT_TEST(testGetBoolAttribute_True); | 19 | CPPUNIT_TEST(testGetBoolAttribute_True); |
| 19 | CPPUNIT_TEST(testGetBoolAttribute_1); | 20 | CPPUNIT_TEST(testGetBoolAttribute_1); |
| 20 | CPPUNIT_TEST(testGetBoolAttribute_False); | 21 | CPPUNIT_TEST(testGetBoolAttribute_False); |
| @@ -34,6 +35,22 @@ class AttributeMapTest : public CppUnit::TestFixture | |||
| 34 | CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace")); | 35 | CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace")); |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 38 | void testGetAttribute_Namespaced_Prefix() { | ||
| 39 | AttributeMap testling; | ||
| 40 | testling.addAttribute("lang", "", "prefix", "nl"); | ||
| 41 | testling.addAttribute("lang", "http://www.w3.org/XML/1998/namespace", "prefix", "en"); | ||
| 42 | testling.addAttribute("lang", "", "prefix", "fr"); | ||
| 43 | |||
| 44 | CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace")); | ||
| 45 | const auto& entries = testling.getEntries(); | ||
| 46 | auto it = std::find_if(entries.begin(), entries.end(), [](const AttributeMap::Entry& e) { | ||
| 47 | return e.getValue() == "en"; | ||
| 48 | }); | ||
| 49 | const bool found = it != entries.end(); | ||
| 50 | CPPUNIT_ASSERT_EQUAL(true, found); | ||
| 51 | CPPUNIT_ASSERT_EQUAL(std::string("prefix"), it->getAttribute().getPrefix()); | ||
| 52 | } | ||
| 53 | |||
| 37 | void testGetBoolAttribute_True() { | 54 | void testGetBoolAttribute_True() { |
| 38 | AttributeMap testling; | 55 | AttributeMap testling; |
| 39 | testling.addAttribute("foo", "", "true"); | 56 | testling.addAttribute("foo", "", "true"); |
diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index 63d30ea..4db694e 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp | |||
| @@ -35,6 +35,7 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 35 | CPPUNIT_TEST(testParse_WhitespaceInAttribute); | 35 | CPPUNIT_TEST(testParse_WhitespaceInAttribute); |
| 36 | CPPUNIT_TEST(testParse_AttributeWithoutNamespace); | 36 | CPPUNIT_TEST(testParse_AttributeWithoutNamespace); |
| 37 | CPPUNIT_TEST(testParse_AttributeWithNamespace); | 37 | CPPUNIT_TEST(testParse_AttributeWithNamespace); |
| 38 | CPPUNIT_TEST(testParse_AttributeWithNamespaceNoPrefix); | ||
| 38 | CPPUNIT_TEST(testParse_BillionLaughs); | 39 | CPPUNIT_TEST(testParse_BillionLaughs); |
| 39 | CPPUNIT_TEST(testParse_InternalEntity); | 40 | CPPUNIT_TEST(testParse_InternalEntity); |
| 40 | //CPPUNIT_TEST(testParse_UndefinedPrefix); | 41 | //CPPUNIT_TEST(testParse_UndefinedPrefix); |
| @@ -43,6 +44,7 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 43 | CPPUNIT_TEST(testParse_DisallowCommentsInXML); | 44 | CPPUNIT_TEST(testParse_DisallowCommentsInXML); |
| 44 | CPPUNIT_TEST(testParse_Doctype); | 45 | CPPUNIT_TEST(testParse_Doctype); |
| 45 | CPPUNIT_TEST(testParse_ProcessingInstructions); | 46 | CPPUNIT_TEST(testParse_ProcessingInstructions); |
| 47 | CPPUNIT_TEST(testParse_ProcessingPrefixedElement); | ||
| 46 | CPPUNIT_TEST_SUITE_END(); | 48 | CPPUNIT_TEST_SUITE_END(); |
| 47 | 49 | ||
| 48 | public: | 50 | public: |
| @@ -264,6 +266,7 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 264 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); | 266 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); |
| 265 | CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); | 267 | CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); |
| 266 | CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); | 268 | CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); |
| 269 | CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); | ||
| 267 | } | 270 | } |
| 268 | 271 | ||
| 269 | void testParse_AttributeWithNamespace() { | 272 | void testParse_AttributeWithNamespace() { |
| @@ -275,6 +278,22 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 275 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); | 278 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); |
| 276 | CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); | 279 | CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); |
| 277 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); | 280 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); |
| 281 | CPPUNIT_ASSERT_EQUAL(std::string("f"), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); | ||
| 282 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); | ||
| 283 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); | ||
| 284 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]); | ||
| 285 | } | ||
| 286 | |||
| 287 | void testParse_AttributeWithNamespaceNoPrefix() { | ||
| 288 | ParserType testling(&client_); | ||
| 289 | |||
| 290 | CPPUNIT_ASSERT(testling.parse( | ||
| 291 | "<query xmlns='http://swift.im' xmlns:f='http://swift.im/f' attr='3'/>")); | ||
| 292 | |||
| 293 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); | ||
| 294 | CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); | ||
| 295 | CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); | ||
| 296 | CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); | ||
| 278 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); | 297 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); |
| 279 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); | 298 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); |
| 280 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]); | 299 | CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]); |
| @@ -373,25 +392,52 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 373 | CPPUNIT_ASSERT(!testling.parse("<?xml-stylesheet type=\"text/xsl\" href=\"Sample.xsl\"?>")); | 392 | CPPUNIT_ASSERT(!testling.parse("<?xml-stylesheet type=\"text/xsl\" href=\"Sample.xsl\"?>")); |
| 374 | } | 393 | } |
| 375 | 394 | ||
| 395 | void testParse_ProcessingPrefixedElement() { | ||
| 396 | client_.testingStartElementPrefix = true; | ||
| 397 | ParserType testling(&client_); | ||
| 398 | |||
| 399 | CPPUNIT_ASSERT(testling.parse("<prefix:message xmlns='uri' xmlns:prefix='uriPrefix'/>")); | ||
| 400 | |||
| 401 | CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); | ||
| 402 | |||
| 403 | CPPUNIT_ASSERT_EQUAL(Client::StartElementPrefix, client_.events[0].type); | ||
| 404 | CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[0].data); | ||
| 405 | CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[0].ns); | ||
| 406 | CPPUNIT_ASSERT_EQUAL(std::string("prefix"), client_.events[0].prefix); | ||
| 407 | |||
| 408 | CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); | ||
| 409 | CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[1].data); | ||
| 410 | CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[1].ns); | ||
| 411 | } | ||
| 412 | |||
| 376 | private: | 413 | private: |
| 377 | class Client : public XMLParserClient { | 414 | class Client : public XMLParserClient { |
| 378 | public: | 415 | public: |
| 379 | using NamespaceMap = std::unordered_map<std::string /* prefix */, std::string /* uri */>; | 416 | using NamespaceMap = std::unordered_map<std::string /* prefix */, std::string /* uri */>; |
| 380 | enum Type { StartElement, EndElement, CharacterData, NamespaceDefined }; | 417 | enum Type { StartElement, StartElementPrefix, EndElement, CharacterData, NamespaceDefined }; |
| 381 | struct Event { | 418 | struct Event { |
| 382 | Event( | 419 | Event( |
| 383 | Type type, | 420 | Type type, |
| 384 | const std::string& data, | 421 | const std::string& data, |
| 385 | const std::string& ns, | 422 | const std::string& ns, |
| 423 | const std::string& prefix, | ||
| 424 | const AttributeMap& attributes, | ||
| 425 | NamespaceMap namespaces) | ||
| 426 | : type(type), data(data), ns(ns), prefix(prefix), attributes(attributes), namespaces(std::move(namespaces)) {} | ||
| 427 | Event( | ||
| 428 | Type type, | ||
| 429 | const std::string& data, | ||
| 430 | const std::string& ns, | ||
| 386 | const AttributeMap& attributes, | 431 | const AttributeMap& attributes, |
| 387 | NamespaceMap namespaces = {}) | 432 | NamespaceMap namespaces = {}) |
| 388 | : type(type), data(data), ns(ns), attributes(attributes), namespaces(std::move(namespaces)) {} | 433 | : Event(type, data, ns, {}, attributes, std::move(namespaces)) {} |
| 389 | Event(Type type, const std::string& data, const std::string& ns = std::string()) | 434 | Event(Type type, const std::string& data, const std::string& ns = std::string()) |
| 390 | : type(type), data(data), ns(ns) {} | 435 | : Event(type, data, ns, "", AttributeMap(), NamespaceMap()) {} |
| 391 | 436 | ||
| 392 | Type type; | 437 | Type type; |
| 393 | std::string data; | 438 | std::string data; |
| 394 | std::string ns; | 439 | std::string ns; |
| 440 | std::string prefix; | ||
| 395 | AttributeMap attributes; | 441 | AttributeMap attributes; |
| 396 | NamespaceMap namespaces; | 442 | NamespaceMap namespaces; |
| 397 | }; | 443 | }; |
| @@ -399,9 +445,15 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 399 | Client() {} | 445 | Client() {} |
| 400 | 446 | ||
| 401 | void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) override { | 447 | void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) override { |
| 448 | if (testingStartElementPrefix) return; | ||
| 402 | events.push_back(Event(StartElement, element, ns, attributes, std::move(namespaces_))); | 449 | events.push_back(Event(StartElement, element, ns, attributes, std::move(namespaces_))); |
| 403 | } | 450 | } |
| 404 | 451 | ||
| 452 | void handleStartElementPrefix(const std::string& prefix, const std::string& uri, const std::string& name, const std::string&, const std::string&, const AttributeMap&) override { | ||
| 453 | if (!testingStartElementPrefix) return; | ||
| 454 | events.push_back(Event(StartElementPrefix, name, uri, prefix, AttributeMap(), NamespaceMap())); | ||
| 455 | } | ||
| 456 | |||
| 405 | void handleEndElement(const std::string& element, const std::string& ns) override { | 457 | void handleEndElement(const std::string& element, const std::string& ns) override { |
| 406 | events.push_back(Event(EndElement, element, ns)); | 458 | events.push_back(Event(EndElement, element, ns)); |
| 407 | } | 459 | } |
| @@ -415,6 +467,7 @@ class XMLParserTest : public CppUnit::TestFixture { | |||
| 415 | } | 467 | } |
| 416 | 468 | ||
| 417 | std::vector<Event> events; | 469 | std::vector<Event> events; |
| 470 | bool testingStartElementPrefix = false; | ||
| 418 | private: | 471 | private: |
| 419 | NamespaceMap namespaces_; | 472 | NamespaceMap namespaces_; |
| 420 | } client_; | 473 | } client_; |
diff --git a/Swiften/Parser/XMLParserClient.cpp b/Swiften/Parser/XMLParserClient.cpp index 40be4e8..847e1f3 100644 --- a/Swiften/Parser/XMLParserClient.cpp +++ b/Swiften/Parser/XMLParserClient.cpp | |||
| @@ -11,6 +11,12 @@ namespace Swift { | |||
| 11 | XMLParserClient::~XMLParserClient() { | 11 | XMLParserClient::~XMLParserClient() { |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | void XMLParserClient::handleStartElement(const std::string&, const std::string&, const AttributeMap&) { | ||
| 15 | } | ||
| 16 | |||
| 17 | void XMLParserClient::handleStartElementPrefix(const std::string&, const std::string&, const std::string&, const std::string&, const std::string&, const AttributeMap&) { | ||
| 18 | } | ||
| 19 | |||
| 14 | void XMLParserClient::handleNamespaceDeclaration(const std::string&, const std::string&) { | 20 | void XMLParserClient::handleNamespaceDeclaration(const std::string&, const std::string&) { |
| 15 | } | 21 | } |
| 16 | 22 | ||
diff --git a/Swiften/Parser/XMLParserClient.h b/Swiften/Parser/XMLParserClient.h index 0682320..f519646 100644 --- a/Swiften/Parser/XMLParserClient.h +++ b/Swiften/Parser/XMLParserClient.h | |||
| @@ -14,7 +14,13 @@ namespace Swift { | |||
| 14 | public: | 14 | public: |
| 15 | virtual ~XMLParserClient(); | 15 | virtual ~XMLParserClient(); |
| 16 | 16 | ||
| 17 | virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) = 0; | 17 | /** |
| 18 | * Client will have to implement only one of the following methods depending on whether | ||
| 19 | * he is interested in processing the element prefix or not. | ||
| 20 | */ | ||
| 21 | virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes); | ||
| 22 | virtual void handleStartElementPrefix(const std::string& prefix, const std::string& uri, const std::string& name, const std::string& element, const std::string& ns, const AttributeMap& attributes); | ||
| 23 | |||
| 18 | virtual void handleEndElement(const std::string& element, const std::string& ns) = 0; | 24 | virtual void handleEndElement(const std::string& element, const std::string& ns) = 0; |
| 19 | virtual void handleCharacterData(const std::string& data) = 0; | 25 | virtual void handleCharacterData(const std::string& data) = 0; |
| 20 | 26 | ||
Swift