From 9f08256dff1766abe43ca2ec70db0ae9f981c286 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Tue, 7 Aug 2007 01:32:38 +0000 Subject: [PATCH] added support for attributes in the xml parser --- include/libtorrent/xml_parse.hpp | 79 +++++++++++++++++++++++++------- src/lsd.cpp | 1 - test/test_primitives.cpp | 38 +++++++++++++++ 3 files changed, 101 insertions(+), 17 deletions(-) diff --git a/include/libtorrent/xml_parse.hpp b/include/libtorrent/xml_parse.hpp index c3aeddad7..ac8c350fa 100644 --- a/include/libtorrent/xml_parse.hpp +++ b/include/libtorrent/xml_parse.hpp @@ -35,9 +35,17 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - const int xml_start_tag = 0; - const int xml_end_tag = 1; - const int xml_string = 2; + enum + { + xml_start_tag = 0, + xml_end_tag = 1, + xml_empty_tag = 2, + xml_string = 3, + xml_attribute = 4 + }; + + // callback(int type, char const* str, char const* str2) + // str2 is only used for attributes. str is name and str2 is value template void xml_parse(char* p, char* end, CallbackType callback) @@ -45,6 +53,8 @@ namespace libtorrent for(;p != end; ++p) { char const* start = p; + char const* val_start = 0; + int token; // look for tag start for(; *p != '<' && p != end; ++p); @@ -55,39 +65,76 @@ namespace libtorrent assert(*p == '<'); *p = 0; } - callback(xml_string, start); + token = xml_string; + callback(token, start, val_start); if (p != end) *p = '<'; } - + if (p == end) break; // skip '<' ++p; - // parse the name of the tag. Ignore attributes - for (start = p; p != end && *p != '>'; ++p) - { - // terminate the string at the first space - // to ignore tag attributes - if (*p == ' ') *p = 0; - } + // parse the name of the tag. + for (start = p; p != end && *p != '>' && *p != ' '; ++p); + + char* tag_name_end = p; + + // skip the attributes for now + for (; p != end && *p != '>'; ++p); // parse error if (p == end) break; assert(*p == '>'); - *p = 0; + // save the character that terminated the tag name + // it could be both '>' and ' '. + char save = *tag_name_end; + *tag_name_end = 0; + char* tag_end = p; if (*start == '/') { ++start; - callback(xml_end_tag, start); + token = xml_end_tag; + callback(token, start, val_start); + } + else if (*(p-1) == '/') + { + *(p-1) = 0; + token = xml_empty_tag; + callback(token, start, val_start); + *(p-1) = '/'; + tag_end = p - 1; } else { - callback(xml_start_tag, start); + token = xml_start_tag; + callback(token, start, val_start); + } + + *tag_name_end = save; + + // parse attributes + start = tag_name_end; + for (char* i = tag_name_end; i < tag_end; ++i) + { + if (*i != '=') continue; + assert(*start == ' '); + ++start; + val_start = i; + for (; i != tag_end && *i != ' '; ++i); + save = *i; + *i = 0; + const_cast(*val_start) = 0; + ++val_start; + token = xml_attribute; + callback(token, start, val_start); + --val_start; + const_cast(*val_start) = '='; + *i = save; + start = i; } - *p = '>'; } } diff --git a/src/lsd.cpp b/src/lsd.cpp index b73e407bc..76f25548d 100644 --- a/src/lsd.cpp +++ b/src/lsd.cpp @@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/lsd.hpp" #include "libtorrent/io.hpp" #include "libtorrent/http_tracker_connection.hpp" -#include "libtorrent/xml_parse.hpp" #include #include #include diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 4c0e410be..b75e5125d 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -1,13 +1,16 @@ #include "libtorrent/tracker_manager.hpp" #include "libtorrent/http_tracker_connection.hpp" #include "libtorrent/buffer.hpp" +#include "libtorrent/xml_parse.hpp" #include #include +#include #include "test.hpp" using namespace libtorrent; using namespace boost::tuples; +using boost::bind; tuple feed_bytes(http_parser& parser, char const* str) { @@ -24,6 +27,24 @@ tuple feed_bytes(http_parser& parser, char const* str) return ret; } +void parser_callback(std::string& out, int token, char const* s, char const* val) +{ + switch (token) + { + case xml_start_tag: out += "B"; break; + case xml_end_tag: out += "F"; break; + case xml_empty_tag: out += "E"; break; + case xml_string: out += "S"; break; + case xml_attribute: out += "A"; break; + } + out += s; + if (token == xml_attribute) + { + out += "V"; + out += val; + } +} + int test_main() { using namespace libtorrent; @@ -96,6 +117,23 @@ int test_main() TEST_CHECK(parser.header("ext") == ""); TEST_CHECK(parser.header("date") == "Fri, 02 Jan 1970 08:10:38 GMT"); + // test xml parser + + char xml1[] = "foobar"; + std::string out1; + + xml_parse(xml1, xml1 + sizeof(xml1) - 1, bind(&parser_callback + , boost::ref(out1), _1, _2, _3)); + std::cerr << out1 << std::endl; + TEST_CHECK(out1 == "BaSfooEbSbarFa"); + + char xml2[] = ""; + std::string out2; + + xml_parse(xml2, xml2 + sizeof(xml2) - 1, bind(&parser_callback + , boost::ref(out2), _1, _2, _3)); + std::cerr << out2 << std::endl; + TEST_CHECK(out2 == "EcAxV1AyV3BdAfooVbarFdAbooVfoo"); return 0; }