forked from premiere/premiere-libtorrent
fix const correctness in xml_parse(). update unit tests rss and upnp to use new signature for parser callback
This commit is contained in:
parent
7e70c41646
commit
cb65694578
|
@ -217,7 +217,8 @@ namespace libtorrent
|
||||||
// are posted to the network thread
|
// are posted to the network thread
|
||||||
struct TORRENT_EXTRA_EXPORT feed : boost::enable_shared_from_this<feed>
|
struct TORRENT_EXTRA_EXPORT feed : boost::enable_shared_from_this<feed>
|
||||||
{
|
{
|
||||||
friend void parse_feed(feed_state& f, int token, char const* name, char const* val);
|
friend void parse_feed(feed_state& f, int token, char const* name, int len
|
||||||
|
, char const* val, int val_len);
|
||||||
|
|
||||||
feed(aux::session_impl& ses, feed_settings const& feed);
|
feed(aux::session_impl& ses, feed_settings const& feed);
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,8 @@ struct parse_state
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TORRENT_EXTRA_EXPORT void find_control_url(int type, char const* string, parse_state& state);
|
TORRENT_EXTRA_EXPORT void find_control_url(int type, char const* string
|
||||||
|
, int str_len, parse_state& state);
|
||||||
|
|
||||||
// TODO: support using the windows API for UPnP operations as well
|
// TODO: support using the windows API for UPnP operations as well
|
||||||
class TORRENT_EXTRA_EXPORT upnp : public boost::enable_shared_from_this<upnp>
|
class TORRENT_EXTRA_EXPORT upnp : public boost::enable_shared_from_this<upnp>
|
||||||
|
|
|
@ -62,11 +62,14 @@ namespace libtorrent
|
||||||
xml_tag_content
|
xml_tag_content
|
||||||
};
|
};
|
||||||
|
|
||||||
// callback(int type, char const* name, char const* val)
|
// callback(int type, char const* name, int name_len
|
||||||
// str2 is only used for attributes. name is element or attribute
|
// , char const* val, int val_len)
|
||||||
// name and val is attribute value
|
// name is element or attribute name
|
||||||
TORRENT_EXTRA_EXPORT void xml_parse(char* p, char* end
|
// val is attribute value
|
||||||
, boost::function<void(int,char const*,char const*)> callback);
|
// neither string is null terminated, but their lengths are specified via
|
||||||
|
// name_len and val_len respectively
|
||||||
|
TORRENT_EXTRA_EXPORT void xml_parse(char const* p, char const* end
|
||||||
|
, boost::function<void(int,char const*,int,char const*,int)> callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c82420cd1b6a83a028f51eeff6d19828136b466c
|
Subproject commit 5924e3b17eb0bdd710027187ccd2952422b25a39
|
51
src/rss.cpp
51
src/rss.cpp
|
@ -166,7 +166,8 @@ struct feed_state
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void parse_feed(feed_state& f, int token, char const* name, char const* val)
|
void parse_feed(feed_state& f, int token, char const* name, int name_len
|
||||||
|
, char const* val, int val_len)
|
||||||
{
|
{
|
||||||
switch (token)
|
switch (token)
|
||||||
{
|
{
|
||||||
|
@ -176,7 +177,7 @@ void parse_feed(feed_state& f, int token, char const* name, char const* val)
|
||||||
case xml_start_tag:
|
case xml_start_tag:
|
||||||
case xml_empty_tag:
|
case xml_empty_tag:
|
||||||
{
|
{
|
||||||
f.current_tag = name;
|
f.current_tag.assign(name, name_len);
|
||||||
if (f.type == feed_state::none)
|
if (f.type == feed_state::none)
|
||||||
{
|
{
|
||||||
if (string_equal_no_case(f.current_tag.c_str(), "feed"))
|
if (string_equal_no_case(f.current_tag.c_str(), "feed"))
|
||||||
|
@ -184,20 +185,21 @@ void parse_feed(feed_state& f, int token, char const* name, char const* val)
|
||||||
else if (string_equal_no_case(f.current_tag.c_str(), "rss"))
|
else if (string_equal_no_case(f.current_tag.c_str(), "rss"))
|
||||||
f.type = feed_state::rss2;
|
f.type = feed_state::rss2;
|
||||||
}
|
}
|
||||||
if (f.is_item(name)) f.in_item = true;
|
if (f.is_item(f.current_tag.c_str())) f.in_item = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case xml_attribute:
|
case xml_attribute:
|
||||||
{
|
{
|
||||||
if (!f.in_item) return;
|
if (!f.in_item) return;
|
||||||
|
std::string str(name, name_len);
|
||||||
if (f.is_url(f.current_tag.c_str())
|
if (f.is_url(f.current_tag.c_str())
|
||||||
&& f.type == feed_state::atom)
|
&& f.type == feed_state::atom)
|
||||||
{
|
{
|
||||||
// atom feeds have items like this:
|
// atom feeds have items like this:
|
||||||
// <link href="http://..." length="12345"/>
|
// <link href="http://..." length="12345"/>
|
||||||
if (string_equal_no_case(name, "href"))
|
if (string_equal_no_case(str.c_str(), "href"))
|
||||||
f.current_item.url = val;
|
f.current_item.url.assign(val, val_len);
|
||||||
else if (string_equal_no_case(name, "length"))
|
else if (string_equal_no_case(str.c_str(), "length"))
|
||||||
f.current_item.size = strtoll(val, 0, 10);
|
f.current_item.size = strtoll(val, 0, 10);
|
||||||
}
|
}
|
||||||
else if (f.type == feed_state::rss2
|
else if (f.type == feed_state::rss2
|
||||||
|
@ -205,9 +207,9 @@ void parse_feed(feed_state& f, int token, char const* name, char const* val)
|
||||||
{
|
{
|
||||||
// rss feeds have items like this:
|
// rss feeds have items like this:
|
||||||
// <enclosure url="http://..." length="12345"/>
|
// <enclosure url="http://..." length="12345"/>
|
||||||
if (string_equal_no_case(name, "url"))
|
if (string_equal_no_case(str.c_str(), "url"))
|
||||||
f.current_item.url = val;
|
f.current_item.url.assign(val, val_len);
|
||||||
else if (string_equal_no_case(name, "length"))
|
else if (string_equal_no_case(str.c_str(), "length"))
|
||||||
f.current_item.size = strtoll(val, 0, 10);
|
f.current_item.size = strtoll(val, 0, 10);
|
||||||
}
|
}
|
||||||
else if (f.type == feed_state::rss2
|
else if (f.type == feed_state::rss2
|
||||||
|
@ -215,16 +217,16 @@ void parse_feed(feed_state& f, int token, char const* name, char const* val)
|
||||||
{
|
{
|
||||||
// rss feeds sometimes have items like this:
|
// rss feeds sometimes have items like this:
|
||||||
// <media:content url="http://..." filesize="12345"/>
|
// <media:content url="http://..." filesize="12345"/>
|
||||||
if (string_equal_no_case(name, "url"))
|
if (string_equal_no_case(str.c_str(), "url"))
|
||||||
f.current_item.url = val;
|
f.current_item.url.assign(val, val_len);
|
||||||
else if (string_equal_no_case(name, "filesize"))
|
else if (string_equal_no_case(str.c_str(), "filesize"))
|
||||||
f.current_item.size = strtoll(val, 0, 10);
|
f.current_item.size = strtoll(val, 0, 10);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case xml_end_tag:
|
case xml_end_tag:
|
||||||
{
|
{
|
||||||
if (f.in_item && f.is_item(name))
|
if (f.in_item && f.is_item(std::string(name, name_len).c_str()))
|
||||||
{
|
{
|
||||||
f.in_item = false;
|
f.in_item = false;
|
||||||
if (!f.current_item.title.empty()
|
if (!f.current_item.title.empty()
|
||||||
|
@ -243,9 +245,9 @@ void parse_feed(feed_state& f, int token, char const* name, char const* val)
|
||||||
if (!f.in_item)
|
if (!f.in_item)
|
||||||
{
|
{
|
||||||
if (f.is_title(f.current_tag.c_str()))
|
if (f.is_title(f.current_tag.c_str()))
|
||||||
f.ret.m_title = name;
|
f.ret.m_title.assign(name, name_len);
|
||||||
else if (f.is_desc(f.current_tag.c_str()))
|
else if (f.is_desc(f.current_tag.c_str()))
|
||||||
f.ret.m_description = name;
|
f.ret.m_description.assign(name, name_len);
|
||||||
else if (f.is_ttl(f.current_tag.c_str()))
|
else if (f.is_ttl(f.current_tag.c_str()))
|
||||||
{
|
{
|
||||||
int tmp = atoi(name);
|
int tmp = atoi(name);
|
||||||
|
@ -254,20 +256,20 @@ void parse_feed(feed_state& f, int token, char const* name, char const* val)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (f.is_title(f.current_tag.c_str()))
|
if (f.is_title(f.current_tag.c_str()))
|
||||||
f.current_item.title = name;
|
f.current_item.title.assign(name, name_len);
|
||||||
else if (f.is_desc(f.current_tag.c_str()))
|
else if (f.is_desc(f.current_tag.c_str()))
|
||||||
f.current_item.description = name;
|
f.current_item.description.assign(name, name_len);
|
||||||
else if (f.is_uuid(f.current_tag.c_str()))
|
else if (f.is_uuid(f.current_tag.c_str()))
|
||||||
f.current_item.uuid = name;
|
f.current_item.uuid.assign(name, name_len);
|
||||||
else if (f.is_url(f.current_tag.c_str()) && f.type != feed_state::atom)
|
else if (f.is_url(f.current_tag.c_str()) && f.type != feed_state::atom)
|
||||||
f.current_item.url = name;
|
f.current_item.url.assign(name, name_len);
|
||||||
else if (f.is_comment(f.current_tag.c_str()))
|
else if (f.is_comment(f.current_tag.c_str()))
|
||||||
f.current_item.comment = name;
|
f.current_item.comment.assign(name, name_len);
|
||||||
else if (f.is_category(f.current_tag.c_str()))
|
else if (f.is_category(f.current_tag.c_str()))
|
||||||
f.current_item.category = name;
|
f.current_item.category.assign(name, name_len);
|
||||||
else if (f.is_size(f.current_tag.c_str()))
|
else if (f.is_size(f.current_tag.c_str()))
|
||||||
f.current_item.size = strtoll(name, 0, 10);
|
f.current_item.size = strtoll(name, 0, 10);
|
||||||
else if (f.is_hash(f.current_tag.c_str()) && strlen(name) == 40)
|
else if (f.is_hash(f.current_tag.c_str()) && name_len == 40)
|
||||||
{
|
{
|
||||||
if (!from_hex(name, 40, f.current_item.info_hash.data()))
|
if (!from_hex(name, 40, f.current_item.info_hash.data()))
|
||||||
{
|
{
|
||||||
|
@ -381,10 +383,9 @@ void feed::on_feed(error_code const& ec
|
||||||
|
|
||||||
m_failures = 0;
|
m_failures = 0;
|
||||||
|
|
||||||
char* buf = const_cast<char*>(data);
|
|
||||||
|
|
||||||
feed_state s(*this);
|
feed_state s(*this);
|
||||||
xml_parse(buf, buf + size, boost::bind(&parse_feed, boost::ref(s), _1, _2, _3));
|
xml_parse(data, data + size, boost::bind(&parse_feed, boost::ref(s)
|
||||||
|
, _1, _2, _3, _4, _5));
|
||||||
|
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
|
||||||
|
|
33
src/upnp.cpp
33
src/upnp.cpp
|
@ -826,19 +826,24 @@ void upnp::delete_port_mapping(rootdevice& d, int i)
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
void copy_tolower(std::string& dst, char const* src)
|
void copy_tolower(std::string& dst, char const* src, int len)
|
||||||
{
|
{
|
||||||
dst.clear();
|
dst.clear();
|
||||||
while (*src) dst.push_back(to_lower(*src++));
|
dst.reserve(len);
|
||||||
|
while (len-- > 0)
|
||||||
|
{
|
||||||
|
dst.push_back(to_lower(*src++));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_EXTRA_EXPORT void find_control_url(int type, char const* string, parse_state& state)
|
TORRENT_EXTRA_EXPORT void find_control_url(int type, char const* string
|
||||||
|
, int str_len, parse_state& state)
|
||||||
{
|
{
|
||||||
if (type == xml_start_tag)
|
if (type == xml_start_tag)
|
||||||
{
|
{
|
||||||
std::string tag;
|
std::string tag;
|
||||||
copy_tolower(tag, string);
|
copy_tolower(tag, string, str_len);
|
||||||
state.tag_stack.push_back(tag);
|
state.tag_stack.push_back(tag);
|
||||||
// std::copy(state.tag_stack.begin(), state.tag_stack.end(), std::ostream_iterator<std::string>(std::cout, " "));
|
// std::copy(state.tag_stack.begin(), state.tag_stack.end(), std::ostream_iterator<std::string>(std::cout, " "));
|
||||||
// std::cout << std::endl;
|
// std::cout << std::endl;
|
||||||
|
@ -858,26 +863,27 @@ TORRENT_EXTRA_EXPORT void find_control_url(int type, char const* string, parse_s
|
||||||
// std::cout << " " << string << std::endl;}
|
// std::cout << " " << string << std::endl;}
|
||||||
if (!state.in_service && state.top_tags("service", "servicetype"))
|
if (!state.in_service && state.top_tags("service", "servicetype"))
|
||||||
{
|
{
|
||||||
if (string_equal_no_case(string, "urn:schemas-upnp-org:service:WANIPConnection:1")
|
std::string name(string, str_len);
|
||||||
|| string_equal_no_case(string, "urn:schemas-upnp-org:service:WANIPConnection:2")
|
if (string_equal_no_case(name.c_str(), "urn:schemas-upnp-org:service:WANIPConnection:1")
|
||||||
|| string_equal_no_case(string, "urn:schemas-upnp-org:service:WANPPPConnection:1"))
|
|| string_equal_no_case(name.c_str(), "urn:schemas-upnp-org:service:WANIPConnection:2")
|
||||||
|
|| string_equal_no_case(name.c_str(), "urn:schemas-upnp-org:service:WANPPPConnection:1"))
|
||||||
{
|
{
|
||||||
state.service_type = string;
|
state.service_type.assign(string, str_len);
|
||||||
state.in_service = true;
|
state.in_service = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (state.control_url.empty() && state.in_service && state.top_tags("service", "controlurl") && strlen(string) > 0)
|
else if (state.control_url.empty() && state.in_service && state.top_tags("service", "controlurl") && strlen(string) > 0)
|
||||||
{
|
{
|
||||||
// default to the first (or only) control url in the router's listing
|
// default to the first (or only) control url in the router's listing
|
||||||
state.control_url = string;
|
state.control_url.assign(string, str_len);
|
||||||
}
|
}
|
||||||
else if (state.model.empty() && state.top_tags("device", "modelname"))
|
else if (state.model.empty() && state.top_tags("device", "modelname"))
|
||||||
{
|
{
|
||||||
state.model = string;
|
state.model.assign(string, str_len);
|
||||||
}
|
}
|
||||||
else if (state.tag_stack.back() == "urlbase")
|
else if (state.tag_stack.back() == "urlbase")
|
||||||
{
|
{
|
||||||
state.url_base = string;
|
state.url_base.assign(string, str_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -928,9 +934,8 @@ void upnp::on_upnp_xml(error_code const& e
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_state s;
|
parse_state s;
|
||||||
xml_parse(const_cast<char*>(p.get_body().begin),
|
xml_parse(p.get_body().begin, p.get_body().end
|
||||||
const_cast<char*>(p.get_body().end)
|
, boost::bind(&find_control_url, _1, _2, _3, boost::ref(s)));
|
||||||
, boost::bind(&find_control_url, _1, _2, boost::ref(s)));
|
|
||||||
if (s.control_url.empty())
|
if (s.control_url.empty())
|
||||||
{
|
{
|
||||||
char msg[500];
|
char msg[500];
|
||||||
|
|
|
@ -37,29 +37,21 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
|
||||||
// TODO: 3 make this take a const buffer instead (and pass in string length
|
TORRENT_EXTRA_EXPORT void xml_parse(char const* p, char const* end
|
||||||
// to callback function). Then remove all associated const_casts.
|
, boost::function<void(int,char const*,int,char const*,int)> callback)
|
||||||
TORRENT_EXTRA_EXPORT void xml_parse(char* p, char* end
|
|
||||||
, boost::function<void(int,char const*,char const*)> callback)
|
|
||||||
{
|
{
|
||||||
for(;p != end; ++p)
|
for(;p != end; ++p)
|
||||||
{
|
{
|
||||||
char const* start = p;
|
char const* start = p;
|
||||||
char const* val_start = 0;
|
|
||||||
int token;
|
int token;
|
||||||
// look for tag start
|
// look for tag start
|
||||||
for(; p != end && *p != '<'; ++p);
|
for(; p != end && *p != '<'; ++p);
|
||||||
|
|
||||||
if (p != start)
|
if (p != start)
|
||||||
{
|
{
|
||||||
if (p != end)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(*p == '<');
|
|
||||||
*p = 0;
|
|
||||||
}
|
|
||||||
token = xml_string;
|
token = xml_string;
|
||||||
callback(token, start, val_start);
|
const int name_len = p - start;
|
||||||
if (p != end) *p = '<';
|
callback(token, start, name_len, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p == end) break;
|
if (p == end) break;
|
||||||
|
@ -78,22 +70,20 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
token = xml_parse_error;
|
token = xml_parse_error;
|
||||||
start = "unexpected end of file";
|
start = "unexpected end of file";
|
||||||
callback(token, start, val_start);
|
callback(token, start, strlen(start), NULL, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
token = xml_string;
|
token = xml_string;
|
||||||
char tmp = p[-2];
|
const int name_len = p - start - 2;
|
||||||
p[-2] = 0;
|
callback(token, start, name_len, NULL, 0);
|
||||||
callback(token, start, val_start);
|
|
||||||
p[-2] = tmp;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the name of the tag.
|
// parse the name of the tag.
|
||||||
for (start = p; p != end && *p != '>' && !is_space(*p); ++p);
|
for (start = p; p != end && *p != '>' && !is_space(*p); ++p);
|
||||||
|
|
||||||
char* tag_name_end = p;
|
char const* tag_name_end = p;
|
||||||
|
|
||||||
// skip the attributes for now
|
// skip the attributes for now
|
||||||
for (; p != end && *p != '>'; ++p);
|
for (; p != end && *p != '>'; ++p);
|
||||||
|
@ -103,68 +93,63 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
token = xml_parse_error;
|
token = xml_parse_error;
|
||||||
start = "unexpected end of file";
|
start = "unexpected end of file";
|
||||||
callback(token, start, val_start);
|
callback(token, start, strlen(start), NULL, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(*p == '>');
|
TORRENT_ASSERT(*p == '>');
|
||||||
// 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;
|
char const* tag_end = p;
|
||||||
if (*start == '/')
|
if (*start == '/')
|
||||||
{
|
{
|
||||||
++start;
|
++start;
|
||||||
token = xml_end_tag;
|
token = xml_end_tag;
|
||||||
callback(token, start, val_start);
|
const int name_len = tag_name_end - start;
|
||||||
|
callback(token, start, name_len, NULL, 0);
|
||||||
}
|
}
|
||||||
else if (*(p-1) == '/')
|
else if (*(p-1) == '/')
|
||||||
{
|
{
|
||||||
*(p-1) = 0;
|
|
||||||
token = xml_empty_tag;
|
token = xml_empty_tag;
|
||||||
callback(token, start, val_start);
|
const int name_len = (std::min)(tag_name_end - start, p - start - 1);
|
||||||
*(p-1) = '/';
|
callback(token, start, name_len, NULL, 0);
|
||||||
tag_end = p - 1;
|
tag_end = p - 1;
|
||||||
}
|
}
|
||||||
else if (*start == '?' && *(p-1) == '?')
|
else if (*start == '?' && *(p-1) == '?')
|
||||||
{
|
{
|
||||||
*(p-1) = 0;
|
|
||||||
++start;
|
++start;
|
||||||
token = xml_declaration_tag;
|
token = xml_declaration_tag;
|
||||||
callback(token, start, val_start);
|
const int name_len = (std::min)(tag_name_end - start, p - start - 1);
|
||||||
*(p-1) = '?';
|
callback(token, start, name_len, NULL, 0);
|
||||||
tag_end = p - 1;
|
tag_end = p - 1;
|
||||||
}
|
}
|
||||||
else if (start + 5 < p && std::memcmp(start, "!--", 3) == 0 && std::memcmp(p-2, "--", 2) == 0)
|
else if (start + 5 < p && std::memcmp(start, "!--", 3) == 0 && std::memcmp(p-2, "--", 2) == 0)
|
||||||
{
|
{
|
||||||
start += 3;
|
start += 3;
|
||||||
*(p-2) = 0;
|
|
||||||
token = xml_comment;
|
token = xml_comment;
|
||||||
callback(token, start, val_start);
|
const int name_len = tag_name_end - start - 2;
|
||||||
*(p-2) = '-';
|
callback(token, start, name_len, NULL, 0);
|
||||||
tag_end = p - 2;
|
tag_end = p - 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
token = xml_start_tag;
|
token = xml_start_tag;
|
||||||
callback(token, start, val_start);
|
const int name_len = tag_name_end - start;
|
||||||
|
callback(token, start, name_len, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
*tag_name_end = save;
|
|
||||||
|
|
||||||
// parse attributes
|
// parse attributes
|
||||||
for (char* i = tag_name_end; i < tag_end; ++i)
|
for (char const* i = tag_name_end; i < tag_end; ++i)
|
||||||
{
|
{
|
||||||
|
char const* val_start = NULL;
|
||||||
|
|
||||||
// find start of attribute name
|
// find start of attribute name
|
||||||
for (; i != tag_end && is_space(*i); ++i);
|
for (; i != tag_end && is_space(*i); ++i);
|
||||||
if (i == tag_end) break;
|
if (i == tag_end) break;
|
||||||
start = i;
|
start = i;
|
||||||
// find end of attribute name
|
// find end of attribute name
|
||||||
for (; i != tag_end && *i != '=' && !is_space(*i); ++i);
|
for (; i != tag_end && *i != '=' && !is_space(*i); ++i);
|
||||||
char* name_end = i;
|
const int name_len = i - start;
|
||||||
|
|
||||||
// look for equality sign
|
// look for equality sign
|
||||||
for (; i != tag_end && *i != '='; ++i);
|
for (; i != tag_end && *i != '='; ++i);
|
||||||
|
@ -173,12 +158,8 @@ namespace libtorrent
|
||||||
// instead of a series of key value pairs
|
// instead of a series of key value pairs
|
||||||
if (i == tag_end)
|
if (i == tag_end)
|
||||||
{
|
{
|
||||||
char tmp = *i;
|
|
||||||
*i = 0; // null terminate the content string
|
|
||||||
token = xml_tag_content;
|
token = xml_tag_content;
|
||||||
val_start = 0;
|
callback(token, start, i - start, NULL, 0);
|
||||||
callback(token, start, val_start);
|
|
||||||
*i = tmp;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,9 +169,8 @@ namespace libtorrent
|
||||||
if (i == tag_end || (*i != '\'' && *i != '\"'))
|
if (i == tag_end || (*i != '\'' && *i != '\"'))
|
||||||
{
|
{
|
||||||
token = xml_parse_error;
|
token = xml_parse_error;
|
||||||
val_start = 0;
|
|
||||||
start = "unquoted attribute value";
|
start = "unquoted attribute value";
|
||||||
callback(token, start, val_start);
|
callback(token, start, strlen(start), NULL, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
char quote = *i;
|
char quote = *i;
|
||||||
|
@ -201,18 +181,13 @@ namespace libtorrent
|
||||||
if (i == tag_end)
|
if (i == tag_end)
|
||||||
{
|
{
|
||||||
token = xml_parse_error;
|
token = xml_parse_error;
|
||||||
val_start = 0;
|
|
||||||
start = "missing end quote on attribute";
|
start = "missing end quote on attribute";
|
||||||
callback(token, start, val_start);
|
callback(token, start, strlen(start), NULL, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
save = *i;
|
const int val_len = i - val_start;
|
||||||
*i = 0;
|
|
||||||
*name_end = 0;
|
|
||||||
token = xml_attribute;
|
token = xml_attribute;
|
||||||
callback(token, start, val_start);
|
callback(token, start, name_len, val_start, val_len);
|
||||||
*name_end = '=';
|
|
||||||
*i = save;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,7 +235,8 @@ char upnp_xml2[] =
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
void parser_callback(std::string& out, int token, char const* s, char const* val)
|
void parser_callback(std::string& out, int token, char const* s, int len
|
||||||
|
, char const* val, int val_len)
|
||||||
{
|
{
|
||||||
switch (token)
|
switch (token)
|
||||||
{
|
{
|
||||||
|
@ -250,154 +251,135 @@ void parser_callback(std::string& out, int token, char const* s, char const* val
|
||||||
case xml_tag_content: out += "T"; break;
|
case xml_tag_content: out += "T"; break;
|
||||||
default: TEST_CHECK(false);
|
default: TEST_CHECK(false);
|
||||||
}
|
}
|
||||||
out += s;
|
out.append(s, len);
|
||||||
if (token == xml_attribute)
|
if (token == xml_attribute)
|
||||||
{
|
{
|
||||||
TEST_CHECK(val != 0);
|
TEST_CHECK(val != NULL);
|
||||||
out += "V";
|
out += "V";
|
||||||
out += val;
|
out.append(val, val_len);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TEST_CHECK(val == 0);
|
TEST_CHECK(val == NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_TEST(xml)
|
void test_parse(char const* in, char const* expected)
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
xml_parse(in, in + strlen(in), boost::bind(&parser_callback
|
||||||
|
, boost::ref(out), _1, _2, _3, _4, _5));
|
||||||
|
fprintf(stderr, "in: %s\n out: %s\nexpected: %s\n"
|
||||||
|
, in, out.c_str(), expected);
|
||||||
|
TEST_EQUAL(out, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(upnp_parser1)
|
||||||
{
|
{
|
||||||
// test upnp xml parser
|
|
||||||
{
|
|
||||||
parse_state xml_s;
|
parse_state xml_s;
|
||||||
xml_parse(upnp_xml, upnp_xml + sizeof(upnp_xml)
|
xml_parse(upnp_xml, upnp_xml + sizeof(upnp_xml)
|
||||||
, boost::bind(&find_control_url, _1, _2, boost::ref(xml_s)));
|
, boost::bind(&find_control_url, _1, _2, _3, boost::ref(xml_s)));
|
||||||
|
|
||||||
std::cerr << "namespace " << xml_s.service_type << std::endl;
|
std::cerr << "namespace " << xml_s.service_type << std::endl;
|
||||||
std::cerr << "url_base: " << xml_s.url_base << std::endl;
|
std::cerr << "url_base: " << xml_s.url_base << std::endl;
|
||||||
std::cerr << "control_url: " << xml_s.control_url << std::endl;
|
std::cerr << "control_url: " << xml_s.control_url << std::endl;
|
||||||
std::cerr << "model: " << xml_s.model << std::endl;
|
std::cerr << "model: " << xml_s.model << std::endl;
|
||||||
TEST_CHECK(xml_s.url_base == "http://192.168.0.1:5678");
|
TEST_EQUAL(xml_s.url_base, "http://192.168.0.1:5678");
|
||||||
TEST_CHECK(xml_s.control_url == "/WANIPConnection");
|
TEST_EQUAL(xml_s.control_url, "/WANIPConnection");
|
||||||
TEST_CHECK(xml_s.model == "D-Link Router");
|
TEST_EQUAL(xml_s.model, "D-Link Router");
|
||||||
}
|
}
|
||||||
{
|
|
||||||
parse_state xml_s;
|
TORRENT_TEST(upnp_parser2)
|
||||||
xml_parse(upnp_xml2, upnp_xml2 + sizeof(upnp_xml2)
|
{
|
||||||
, boost::bind(&find_control_url, _1, _2, boost::ref(xml_s)));
|
parse_state xml_s;
|
||||||
|
xml_parse(upnp_xml2, upnp_xml2 + sizeof(upnp_xml2)
|
||||||
std::cerr << "namespace " << xml_s.service_type << std::endl;
|
, boost::bind(&find_control_url, _1, _2, _3, boost::ref(xml_s)));
|
||||||
std::cerr << "url_base: " << xml_s.url_base << std::endl;
|
|
||||||
std::cerr << "control_url: " << xml_s.control_url << std::endl;
|
std::cerr << "namespace " << xml_s.service_type << std::endl;
|
||||||
std::cerr << "model: " << xml_s.model << std::endl;
|
std::cerr << "url_base: " << xml_s.url_base << std::endl;
|
||||||
TEST_CHECK(xml_s.url_base == "http://192.168.1.1:49152");
|
std::cerr << "control_url: " << xml_s.control_url << std::endl;
|
||||||
TEST_CHECK(xml_s.control_url == "/upnp/control/WANPPPConn1");
|
std::cerr << "model: " << xml_s.model << std::endl;
|
||||||
TEST_CHECK(xml_s.model == "Wireless-G ADSL Home Gateway");
|
TEST_EQUAL(xml_s.url_base, "http://192.168.1.1:49152");
|
||||||
}
|
TEST_EQUAL(xml_s.control_url, "/upnp/control/WANPPPConn1");
|
||||||
|
TEST_EQUAL(xml_s.model, "Wireless-G ADSL Home Gateway");
|
||||||
{
|
}
|
||||||
// test xml parser
|
|
||||||
char xml[] = "<a>foo<b/>bar</a>";
|
TORRENT_TEST(tags)
|
||||||
std::string out;
|
{
|
||||||
|
test_parse("<a>foo<b/>bar</a>", "BaSfooEbSbarFa");
|
||||||
xml_parse(xml, xml + sizeof(xml) - 1, boost::bind(&parser_callback
|
}
|
||||||
, boost::ref(out), _1, _2, _3));
|
|
||||||
std::cerr << out << std::endl;
|
TORRENT_TEST(xml_tag_comment)
|
||||||
TEST_CHECK(out == "BaSfooEbSbarFa");
|
{
|
||||||
}
|
test_parse("<?xml version = \"1.0\"?><c x=\"1\" \t y=\"3\"/><d foo='bar'></d boo='foo'><!--comment-->"
|
||||||
|
, "DxmlAversionV1.0EcAxV1AyV3BdAfooVbarFdAbooVfooCcomment");
|
||||||
{
|
}
|
||||||
char xml[] = "<?xml version = \"1.0\"?><c x=\"1\" \t y=\"3\"/><d foo='bar'></d boo='foo'><!--comment-->";
|
|
||||||
std::string out;
|
TORRENT_TEST(empty_tag)
|
||||||
|
{
|
||||||
xml_parse(xml, xml + sizeof(xml) - 1, boost::bind(&parser_callback
|
test_parse("<foo/>", "Efoo");
|
||||||
, boost::ref(out), _1, _2, _3));
|
}
|
||||||
std::cerr << out << std::endl;
|
|
||||||
TEST_CHECK(out == "DxmlAversionV1.0EcAxV1AyV3BdAfooVbarFdAbooVfooCcomment");
|
TORRENT_TEST(empty_tag_whitespace)
|
||||||
}
|
{
|
||||||
|
test_parse("<foo />", "Efoo");
|
||||||
{
|
}
|
||||||
char xml[] = "<a f=1>foo</a f='b>";
|
|
||||||
std::string out;
|
TORRENT_TEST(xml_tag_no_attribute)
|
||||||
|
{
|
||||||
xml_parse(xml, xml + sizeof(xml) - 1, boost::bind(&parser_callback
|
test_parse("<?xml?>", "Dxml");
|
||||||
, boost::ref(out), _1, _2, _3));
|
}
|
||||||
std::cerr << out << std::endl;
|
|
||||||
TEST_CHECK(out == "BaPunquoted attribute valueSfooFaPmissing end quote on attribute");
|
TORRENT_TEST(xml_tag_no_attribute_whitespace)
|
||||||
}
|
{
|
||||||
|
test_parse("<?xml ?>", "Dxml");
|
||||||
{
|
}
|
||||||
char xml[] = "<a f>foo</a v >";
|
|
||||||
std::string out;
|
TORRENT_TEST(attribute_missing_qoute)
|
||||||
|
{
|
||||||
xml_parse(xml, xml + sizeof(xml) - 1, boost::bind(&parser_callback
|
test_parse("<a f=1>foo</a f='b>"
|
||||||
, boost::ref(out), _1, _2, _3));
|
, "BaPunquoted attribute valueSfooFaPmissing end quote on attribute");
|
||||||
std::cerr << out << std::endl;
|
}
|
||||||
TEST_CHECK(out == "BaTfSfooFaTv ");
|
|
||||||
}
|
TORRENT_TEST(attribute_whitespace)
|
||||||
|
{
|
||||||
{
|
test_parse("<a f>foo</a v >", "BaTfSfooFaTv ");
|
||||||
// test unterminated CDATA tags
|
}
|
||||||
char xml[] = "<![CDATA[foo";
|
|
||||||
std::string out;
|
TORRENT_TEST(unterminated_cdata)
|
||||||
|
{
|
||||||
xml_parse(xml, xml + sizeof(xml) - 1, boost::bind(&parser_callback
|
// test unterminated CDATA tags
|
||||||
, boost::ref(out), _1, _2, _3));
|
test_parse("<![CDATA[foo", "Punexpected end of file");
|
||||||
std::cerr << out << std::endl;
|
}
|
||||||
TEST_CHECK(out == "Punexpected end of file");
|
|
||||||
}
|
TORRENT_TEST(cdata)
|
||||||
|
{
|
||||||
{
|
// test CDATA tag
|
||||||
// test CDATA tag
|
test_parse("<![CDATA[verbatim tag that can have > and < in it]]>"
|
||||||
char xml[] = "<![CDATA[verbatim tag that can have > and < in it]]>";
|
, "Sverbatim tag that can have > and < in it");
|
||||||
std::string out;
|
}
|
||||||
|
|
||||||
xml_parse(xml, xml + sizeof(xml) - 1, boost::bind(&parser_callback
|
TORRENT_TEST(unterminated_tag)
|
||||||
, boost::ref(out), _1, _2, _3));
|
{
|
||||||
std::cerr << out << std::endl;
|
// test unterminated tags
|
||||||
TEST_CHECK(out == "Sverbatim tag that can have > and < in it");
|
test_parse("<foo", "Punexpected end of file");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
TORRENT_TEST(unqouted_attribute_value)
|
||||||
// test unterminated tags
|
{
|
||||||
char xml[] = "<foo";
|
// test unquoted attribute values
|
||||||
std::string out;
|
test_parse("<foo a=bar>", "BfooPunquoted attribute value");
|
||||||
|
}
|
||||||
xml_parse(xml, xml + sizeof(xml) - 1, boost::bind(&parser_callback
|
|
||||||
, boost::ref(out), _1, _2, _3));
|
TORRENT_TEST(unterminated_attribute)
|
||||||
std::cerr << out << std::endl;
|
{
|
||||||
TEST_CHECK(out == "Punexpected end of file");
|
// test unterminated attribute value
|
||||||
}
|
test_parse("<foo a=\"bar>", "BfooPmissing end quote on attribute");
|
||||||
|
}
|
||||||
{
|
|
||||||
// test unquoted attribute values
|
TORRENT_TEST(unterminated_tag_with_attribute)
|
||||||
char xml[] = "<foo a=bar>";
|
{
|
||||||
std::string out;
|
// test unterminated tag
|
||||||
|
test_parse("<foo a=\"bar", "Punexpected end of file");
|
||||||
xml_parse(xml, xml + sizeof(xml) - 1, boost::bind(&parser_callback
|
|
||||||
, boost::ref(out), _1, _2, _3));
|
|
||||||
std::cerr << out << std::endl;
|
|
||||||
TEST_CHECK(out == "BfooPunquoted attribute value");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// test unterminated attribute value
|
|
||||||
char xml[] = "<foo a=\"bar>";
|
|
||||||
std::string out;
|
|
||||||
|
|
||||||
xml_parse(xml, xml + sizeof(xml) - 1, boost::bind(&parser_callback
|
|
||||||
, boost::ref(out), _1, _2, _3));
|
|
||||||
std::cerr << out << std::endl;
|
|
||||||
TEST_CHECK(out == "BfooPmissing end quote on attribute");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// test unterminated tag
|
|
||||||
char xml[] = "<foo a=\"bar";
|
|
||||||
std::string out;
|
|
||||||
|
|
||||||
xml_parse(xml, xml + sizeof(xml) - 1, boost::bind(&parser_callback
|
|
||||||
, boost::ref(out), _1, _2, _3));
|
|
||||||
std::cerr << out << std::endl;
|
|
||||||
TEST_CHECK(out == "Punexpected end of file");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue