/* */ #include "bencode2.h" #include #include #include "StringFormat.h" #include "DlAbortEx.h" namespace aria2 { namespace bencode2 { static SharedHandle decodeiter(std::istream& ss, size_t depth); static void checkdelim(std::istream& ss, const char delim = ':') { char d; if(!(ss.get(d) && d == delim)) { throw DL_ABORT_EX (StringFormat("Bencode decoding failed: Delimiter '%c' not found.", delim).str()); } } static std::string decoderawstring(std::istream& ss) { int length; ss >> length; if(!ss || length < 0) { throw DL_ABORT_EX("Bencode decoding failed:" " A positive integer expected but none found."); } // 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(length)) { throw DL_ABORT_EX (StringFormat("Bencode decoding failed:" " Expected %lu bytes of data, but only %d read.", static_cast(length), ss.gcount()).str()); } return str; } static SharedHandle decodestring(std::istream& ss) { return String::g(decoderawstring(ss)); } static SharedHandle decodeinteger(std::istream& ss) { Integer::ValueType iv; ss >> iv; if(!ss) { throw DL_ABORT_EX("Bencode decoding failed:" " Integer expected but none found"); } checkdelim(ss, 'e'); return Integer::g(iv); } static SharedHandle decodedict(std::istream& ss, size_t depth) { SharedHandle dict = Dict::g(); char c; while(ss.get(c)) { if(c == 'e') { return dict; } else { ss.unget(); std::string key = decoderawstring(ss); dict->put(key, decodeiter(ss, depth)); } } throw DL_ABORT_EX("Bencode decoding failed:" " Unexpected EOF in dict context. 'e' expected."); } static SharedHandle decodelist(std::istream& ss, size_t depth) { SharedHandle list = List::g(); char c; while(ss.get(c)) { if(c == 'e') { return list; } else { ss.unget(); list->append(decodeiter(ss, depth)); } } throw DL_ABORT_EX("Bencode decoding failed:" " Unexpected EOF in list context. 'e' expected."); } static void checkDepth(size_t depth) { if(depth >= MAX_STRUCTURE_DEPTH) { throw DL_ABORT_EX("Bencode decoding failed: Structure is too deep."); } } static SharedHandle decodeiter(std::istream& ss, size_t depth) { checkDepth(depth); char c; if(!ss.get(c)) { throw DL_ABORT_EX("Bencode decoding failed:" " Unexpected EOF in term context." " 'd', 'l', 'i' or digit is expected."); } if(c == 'd') { return decodedict(ss, depth+1); } else if(c == 'l') { return decodelist(ss, depth+1); } else if(c == 'i') { return decodeinteger(ss); } else { ss.unget(); return decodestring(ss); } } SharedHandle decode(std::istream& in) { return decodeiter(in, 0); } SharedHandle decode(const std::string& s) { size_t end; return decode(s, end); } SharedHandle decode(const std::string& s, size_t& end) { if(s.empty()) { return SharedHandle(); } std::istringstream ss(s); SharedHandle vlb = decodeiter(ss, 0); end = ss.tellg(); return vlb; } SharedHandle decode(const unsigned char* data, size_t length) { return decode(std::string(&data[0], &data[length])); } SharedHandle decode(const unsigned char* data, size_t length, size_t& end) { return decode(std::string(&data[0], &data[length]), end); } SharedHandle decodeFromFile(const std::string& filename) { std::ifstream f(filename.c_str(), std::ios::binary); if(f) { return decode(f); } else { throw DL_ABORT_EX (StringFormat("Bencode decoding failed:" " Cannot open file '%s'.", filename.c_str()).str()); } } std::string encode(const ValueBase* vlb) { class BencodeValueBaseVisitor:public ValueBaseVisitor { private: std::ostringstream out_; public: virtual void visit(const String& string) { const std::string& s = string.s(); out_ << s.size() << ":"; out_.write(s.data(), s.size()); } virtual void visit(const Integer& integer) { out_ << "i" << integer.i() << "e"; } virtual void visit(const List& list) { out_ << "l"; for(List::ValueType::const_iterator i = list.begin(), eoi = list.end(); i != eoi; ++i){ (*i)->accept(*this); } out_ << "e"; } virtual void visit(const Dict& dict) { out_ << "d"; for(Dict::ValueType::const_iterator i = dict.begin(), eoi = dict.end(); i != eoi; ++i){ const std::string& key = (*i).first; out_ << key.size() << ":"; out_.write(key.data(), key.size()); (*i).second->accept(*this); } out_ << "e"; } std::string getResult() const { return out_.str(); } }; BencodeValueBaseVisitor visitor; vlb->accept(visitor); return visitor.getResult(); } std::string encode(const SharedHandle& vlb) { return encode(vlb.get()); } } // namespace bencode2 } // namespace aria2