added support for attributes in the xml parser
This commit is contained in:
@@ -35,9 +35,17 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
const int xml_start_tag = 0;
|
enum
|
||||||
const int xml_end_tag = 1;
|
{
|
||||||
const int xml_string = 2;
|
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 <class CallbackType>
|
template <class CallbackType>
|
||||||
void xml_parse(char* p, char* end, CallbackType callback)
|
void xml_parse(char* p, char* end, CallbackType callback)
|
||||||
@@ -45,6 +53,8 @@ namespace libtorrent
|
|||||||
for(;p != end; ++p)
|
for(;p != end; ++p)
|
||||||
{
|
{
|
||||||
char const* start = p;
|
char const* start = p;
|
||||||
|
char const* val_start = 0;
|
||||||
|
int token;
|
||||||
// look for tag start
|
// look for tag start
|
||||||
for(; *p != '<' && p != end; ++p);
|
for(; *p != '<' && p != end; ++p);
|
||||||
|
|
||||||
@@ -55,7 +65,8 @@ namespace libtorrent
|
|||||||
assert(*p == '<');
|
assert(*p == '<');
|
||||||
*p = 0;
|
*p = 0;
|
||||||
}
|
}
|
||||||
callback(xml_string, start);
|
token = xml_string;
|
||||||
|
callback(token, start, val_start);
|
||||||
if (p != end) *p = '<';
|
if (p != end) *p = '<';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,30 +75,66 @@ namespace libtorrent
|
|||||||
// skip '<'
|
// skip '<'
|
||||||
++p;
|
++p;
|
||||||
|
|
||||||
// parse the name of the tag. Ignore attributes
|
// parse the name of the tag.
|
||||||
for (start = p; p != end && *p != '>'; ++p)
|
for (start = p; p != end && *p != '>' && *p != ' '; ++p);
|
||||||
{
|
|
||||||
// terminate the string at the first space
|
char* tag_name_end = p;
|
||||||
// to ignore tag attributes
|
|
||||||
if (*p == ' ') *p = 0;
|
// skip the attributes for now
|
||||||
}
|
for (; p != end && *p != '>'; ++p);
|
||||||
|
|
||||||
// parse error
|
// parse error
|
||||||
if (p == end) break;
|
if (p == end) break;
|
||||||
|
|
||||||
assert(*p == '>');
|
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 == '/')
|
if (*start == '/')
|
||||||
{
|
{
|
||||||
++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
|
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<char&>(*val_start) = 0;
|
||||||
|
++val_start;
|
||||||
|
token = xml_attribute;
|
||||||
|
callback(token, start, val_start);
|
||||||
|
--val_start;
|
||||||
|
const_cast<char&>(*val_start) = '=';
|
||||||
|
*i = save;
|
||||||
|
start = i;
|
||||||
}
|
}
|
||||||
*p = '>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/lsd.hpp"
|
#include "libtorrent/lsd.hpp"
|
||||||
#include "libtorrent/io.hpp"
|
#include "libtorrent/io.hpp"
|
||||||
#include "libtorrent/http_tracker_connection.hpp"
|
#include "libtorrent/http_tracker_connection.hpp"
|
||||||
#include "libtorrent/xml_parse.hpp"
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/ref.hpp>
|
#include <boost/ref.hpp>
|
||||||
#include <asio/ip/host_name.hpp>
|
#include <asio/ip/host_name.hpp>
|
||||||
|
@@ -1,13 +1,16 @@
|
|||||||
#include "libtorrent/tracker_manager.hpp"
|
#include "libtorrent/tracker_manager.hpp"
|
||||||
#include "libtorrent/http_tracker_connection.hpp"
|
#include "libtorrent/http_tracker_connection.hpp"
|
||||||
#include "libtorrent/buffer.hpp"
|
#include "libtorrent/buffer.hpp"
|
||||||
|
#include "libtorrent/xml_parse.hpp"
|
||||||
#include <boost/tuple/tuple.hpp>
|
#include <boost/tuple/tuple.hpp>
|
||||||
#include <boost/tuple/tuple_comparison.hpp>
|
#include <boost/tuple/tuple_comparison.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
using namespace boost::tuples;
|
using namespace boost::tuples;
|
||||||
|
using boost::bind;
|
||||||
|
|
||||||
tuple<int, int> feed_bytes(http_parser& parser, char const* str)
|
tuple<int, int> feed_bytes(http_parser& parser, char const* str)
|
||||||
{
|
{
|
||||||
@@ -24,6 +27,24 @@ tuple<int, int> feed_bytes(http_parser& parser, char const* str)
|
|||||||
return ret;
|
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()
|
int test_main()
|
||||||
{
|
{
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
@@ -96,6 +117,23 @@ int test_main()
|
|||||||
TEST_CHECK(parser.header<std::string>("ext") == "");
|
TEST_CHECK(parser.header<std::string>("ext") == "");
|
||||||
TEST_CHECK(parser.header<std::string>("date") == "Fri, 02 Jan 1970 08:10:38 GMT");
|
TEST_CHECK(parser.header<std::string>("date") == "Fri, 02 Jan 1970 08:10:38 GMT");
|
||||||
|
|
||||||
|
// test xml parser
|
||||||
|
|
||||||
|
char xml1[] = "<a>foo<b/>bar</a>";
|
||||||
|
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[] = "<c x=1 y=3/><d foo=bar></d boo=foo>";
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user