summaryrefslogtreecommitdiff
path: root/src/bencode2.cc
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2011-11-05 12:01:57 +0900
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2011-11-05 12:01:57 +0900
commitd1d49036651012433595357ca31e6f65dbec3a6b (patch)
treea962461fc219fa02458d154eef4e3a354bb99e40 /src/bencode2.cc
parentd305432ec0015cfc9479331531a78f29c398bd8c (diff)
Rewritten bencode2::decode functions
Diffstat (limited to 'src/bencode2.cc')
-rw-r--r--src/bencode2.cc189
1 files changed, 109 insertions, 80 deletions
diff --git a/src/bencode2.cc b/src/bencode2.cc
index 181309a8..1db0ddbe 100644
--- a/src/bencode2.cc
+++ b/src/bencode2.cc
@@ -40,90 +40,92 @@
#include "DlAbortEx.h"
#include "error_code.h"
#include "BufferedFile.h"
+#include "util.h"
namespace aria2 {
namespace bencode2 {
namespace {
-SharedHandle<ValueBase> decodeiter(std::istream& ss, size_t depth);
+template<typename InputIterator>
+std::pair<SharedHandle<ValueBase>, InputIterator>
+decodeiter
+(InputIterator first,
+ InputIterator last,
+ size_t depth);
} // namespace
namespace {
-void checkdelim(std::istream& ss, const char delim = ':')
+template<typename InputIterator>
+std::pair<std::string, InputIterator>
+decoderawstring(InputIterator first, InputIterator last)
{
- char d;
- if(!(ss.get(d) && d == delim)) {
- throw DL_ABORT_EX2
- (fmt("Bencode decoding failed: Delimiter '%c' not found.",
- delim),
- error_code::BENCODE_PARSE_ERROR);
- }
-}
-} // namespace
-
-namespace {
-std::string decoderawstring(std::istream& ss)
-{
- int length;
- ss >> length;
- if(!ss || length < 0) {
+ InputIterator i = first;
+ int32_t len;
+ for(; i != last && *i != ':'; ++i);
+ if(i == last || i == first || !util::parseIntNoThrow(len, first, i) ||
+ len < 0) {
throw DL_ABORT_EX2("Bencode decoding failed:"
" A positive integer expected but none found.",
error_code::BENCODE_PARSE_ERROR);
}
- // TODO check length, it must be less than or equal to INT_MAX
- checkdelim(ss);
- char* buf = new char[length];
- ss.read(buf, length);
- std::string str(&buf[0], &buf[length]);
- delete [] buf;
- if(ss.gcount() != static_cast<int>(length)) {
+ ++i;
+ if(last-i < len) {
throw DL_ABORT_EX2
(fmt("Bencode decoding failed:"
- " Expected %lu bytes of data, but only %ld read.",
- static_cast<unsigned long>(length),
- static_cast<long int>(ss.gcount())),
+ " Expected %d bytes of data, but only %d read.",
+ len, static_cast<int>(last-i)),
error_code::BENCODE_PARSE_ERROR);
}
- return str;
+ return std::make_pair(std::string(i, i+len), i+len);
}
} // namespace
namespace {
-SharedHandle<ValueBase> decodestring(std::istream& ss)
+template<typename InputIterator>
+std::pair<SharedHandle<ValueBase>, InputIterator>
+decodestring(InputIterator first, InputIterator last)
{
- return String::g(decoderawstring(ss));
+ std::pair<std::string, InputIterator> r = decoderawstring(first, last);
+ return std::make_pair(String::g(r.first), r.second);
}
} // namespace
namespace {
-SharedHandle<ValueBase> decodeinteger(std::istream& ss)
+template<typename InputIterator>
+std::pair<SharedHandle<ValueBase>, InputIterator>
+decodeinteger(InputIterator first, InputIterator last)
{
+ InputIterator i = first;
+ for(; i != last && *i != 'e'; ++i);
Integer::ValueType iv;
- ss >> iv;
- if(!ss) {
+ if(i == last || !util::parseLLIntNoThrow(iv, first, i)) {
throw DL_ABORT_EX2("Bencode decoding failed:"
" Integer expected but none found",
error_code::BENCODE_PARSE_ERROR);
}
- checkdelim(ss, 'e');
- return Integer::g(iv);
+ return std::make_pair(Integer::g(iv), ++i);
}
} // namespace
namespace {
-SharedHandle<ValueBase> decodedict(std::istream& ss, size_t depth)
+template<typename InputIterator>
+std::pair<SharedHandle<ValueBase>, InputIterator>
+decodedict
+(InputIterator first,
+ InputIterator last,
+ size_t depth)
{
SharedHandle<Dict> dict = Dict::g();
- char c;
- while(ss.get(c)) {
- if(c == 'e') {
- return dict;
+ while(first != last) {
+ if(*first == 'e') {
+ return std::make_pair(dict, ++first);
} else {
- ss.unget();
- std::string key = decoderawstring(ss);
- dict->put(key, decodeiter(ss, depth));
+ std::pair<std::string, InputIterator> keyp = decoderawstring(first, last);
+ std::pair<SharedHandle<ValueBase>, InputIterator> r =
+ decodeiter(keyp.second, last, depth);
+ dict->put(keyp.first, r.first);
+ first = r.second;
}
}
throw DL_ABORT_EX2("Bencode decoding failed:"
@@ -133,16 +135,22 @@ SharedHandle<ValueBase> decodedict(std::istream& ss, size_t depth)
} // namespace
namespace {
-SharedHandle<ValueBase> decodelist(std::istream& ss, size_t depth)
+template<typename InputIterator>
+std::pair<SharedHandle<ValueBase>, InputIterator>
+decodelist
+(InputIterator first,
+ InputIterator last,
+ size_t depth)
{
SharedHandle<List> list = List::g();
- char c;
- while(ss.get(c)) {
- if(c == 'e') {
- return list;
+ while(first != last) {
+ if(*first == 'e') {
+ return std::make_pair(list, ++first);
} else {
- ss.unget();
- list->append(decodeiter(ss, depth));
+ std::pair<SharedHandle<ValueBase>, InputIterator> r =
+ decodeiter(first, last, depth);
+ list->append(r.first);
+ first = r.second;
}
}
throw DL_ABORT_EX2("Bencode decoding failed:"
@@ -162,60 +170,79 @@ void checkDepth(size_t depth)
} // namespace
namespace {
-SharedHandle<ValueBase> decodeiter(std::istream& ss, size_t depth)
+template<typename InputIterator>
+std::pair<SharedHandle<ValueBase>, InputIterator>
+decodeiter
+(InputIterator first,
+ InputIterator last,
+ size_t depth)
{
checkDepth(depth);
- char c;
- if(!ss.get(c)) {
+ if(first == last) {
throw DL_ABORT_EX2("Bencode decoding failed:"
" Unexpected EOF in term context."
" 'd', 'l', 'i' or digit is expected.",
error_code::BENCODE_PARSE_ERROR);
}
- if(c == 'd') {
- return decodedict(ss, depth+1);
- } else if(c == 'l') {
- return decodelist(ss, depth+1);
- } else if(c == 'i') {
- return decodeinteger(ss);
+ if(*first == 'd') {
+ return decodedict(++first, last, depth+1);
+ } else if(*first == 'l') {
+ return decodelist(++first, last, depth+1);
+ } else if(*first == 'i') {
+ return decodeinteger(++first, last);
} else {
- ss.unget();
- return decodestring(ss);
+ return decodestring(first, last);
}
}
} // namespace
-SharedHandle<ValueBase> decode(std::istream& in)
+namespace {
+template<typename InputIterator>
+SharedHandle<ValueBase> decodegen
+(InputIterator first,
+ InputIterator last,
+ size_t& end)
{
- return decodeiter(in, 0);
+ if(first == last) {
+ return SharedHandle<ValueBase>();
+ }
+ std::pair<SharedHandle<ValueBase>, InputIterator> p =
+ decodeiter(first, last, 0);
+ end = p.second-first;
+ return p.first;
}
+} // namespace
-SharedHandle<ValueBase> decode(const std::string& s)
+SharedHandle<ValueBase> decode
+(std::string::const_iterator first,
+ std::string::const_iterator last)
{
size_t end;
- return decode(s, end);
+ return decodegen(first, last, end);
}
-SharedHandle<ValueBase> decode(const std::string& s, size_t& end)
+SharedHandle<ValueBase> decode
+(std::string::const_iterator first,
+ std::string::const_iterator last,
+ size_t& end)
{
- if(s.empty()) {
- return SharedHandle<ValueBase>();
- }
- std::istringstream ss(s);
-
- SharedHandle<ValueBase> vlb = decodeiter(ss, 0);
- end = ss.tellg();
- return vlb;
+ return decodegen(first, last, end);
}
-SharedHandle<ValueBase> decode(const unsigned char* data, size_t length)
+SharedHandle<ValueBase> decode
+(const unsigned char* first,
+ const unsigned char* last)
{
- return decode(std::string(&data[0], &data[length]));
+ size_t end;
+ return decodegen(first, last, end);
}
-SharedHandle<ValueBase> decode(const unsigned char* data, size_t length, size_t& end)
+SharedHandle<ValueBase> decode
+(const unsigned char* first,
+ const unsigned char* last,
+ size_t& end)
{
- return decode(std::string(&data[0], &data[length]), end);
+ return decodegen(first, last, end);
}
SharedHandle<ValueBase> decodeFromFile(const std::string& filename)
@@ -225,7 +252,9 @@ SharedHandle<ValueBase> decodeFromFile(const std::string& filename)
std::stringstream ss;
fp.transfer(ss);
fp.close();
- return decode(ss);
+ const std::string s = ss.str();
+ size_t end;
+ return decodegen(s.begin(), s.end(), end);
} else {
throw DL_ABORT_EX2
(fmt("Bencode decoding failed: Cannot open file '%s'.",