00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #ifndef TORRENT_BENCODE_HPP_INCLUDED
00035 #define TORRENT_BENCODE_HPP_INCLUDED
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 #include <cstdlib>
00067
00068 #ifdef _MSC_VER
00069 #pragma warning(push, 1)
00070 #endif
00071
00072 #include <boost/lexical_cast.hpp>
00073 #include <boost/static_assert.hpp>
00074
00075 #ifdef _MSC_VER
00076 #pragma warning(pop)
00077 #endif
00078
00079 #include "libtorrent/entry.hpp"
00080 #include "libtorrent/config.hpp"
00081
00082 #if defined(_MSC_VER)
00083 namespace std
00084 {
00085 using ::isdigit;
00086 using ::atoi;
00087 };
00088
00089 #define for if (false) {} else for
00090 #endif
00091
00092
00093 namespace libtorrent
00094 {
00095
00096 struct TORRENT_EXPORT invalid_encoding: std::exception
00097 {
00098 virtual const char* what() const throw() { return "invalid bencoding"; }
00099 };
00100
00101 namespace detail
00102 {
00103 template <class OutIt>
00104 void write_string(OutIt& out, const std::string& val)
00105 {
00106 std::string::const_iterator end = val.begin() + val.length();
00107 std::copy(val.begin(), end, out);
00108 }
00109
00110 TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val);
00111
00112 template <class OutIt>
00113 void write_integer(OutIt& out, entry::integer_type val)
00114 {
00115
00116
00117
00118 BOOST_STATIC_ASSERT(sizeof(entry::integer_type) <= 8);
00119 char buf[21];
00120 for (char const* str = integer_to_str(buf, 21, val);
00121 *str != 0; ++str)
00122 {
00123 *out = *str;
00124 ++out;
00125 }
00126 }
00127
00128 template <class OutIt>
00129 void write_char(OutIt& out, char c)
00130 {
00131 *out = c;
00132 ++out;
00133 }
00134
00135 template <class InIt>
00136 std::string read_until(InIt& in, InIt end, char end_token)
00137 {
00138 if (in == end) throw invalid_encoding();
00139 std::string ret;
00140 while (*in != end_token)
00141 {
00142 ret += *in;
00143 ++in;
00144 if (in == end) throw invalid_encoding();
00145 }
00146 return ret;
00147 }
00148
00149 template<class InIt>
00150 void read_string(InIt& in, InIt end, int len, std::string& str)
00151 {
00152 assert(len >= 0);
00153 for (int i = 0; i < len; ++i)
00154 {
00155 if (in == end) throw invalid_encoding();
00156 str += *in;
00157 ++in;
00158 }
00159 }
00160
00161 template<class OutIt>
00162 void bencode_recursive(OutIt& out, const entry& e)
00163 {
00164 switch(e.type())
00165 {
00166 case entry::int_t:
00167 write_char(out, 'i');
00168 write_integer(out, e.integer());
00169 write_char(out, 'e');
00170 break;
00171 case entry::string_t:
00172 write_integer(out, e.string().length());
00173 write_char(out, ':');
00174 write_string(out, e.string());
00175 break;
00176 case entry::list_t:
00177 write_char(out, 'l');
00178 for (entry::list_type::const_iterator i = e.list().begin(); i != e.list().end(); ++i)
00179 bencode_recursive(out, *i);
00180 write_char(out, 'e');
00181 break;
00182 case entry::dictionary_t:
00183 write_char(out, 'd');
00184 for (entry::dictionary_type::const_iterator i = e.dict().begin();
00185 i != e.dict().end(); ++i)
00186 {
00187
00188 write_integer(out, i->first.length());
00189 write_char(out, ':');
00190 write_string(out, i->first);
00191
00192 bencode_recursive(out, i->second);
00193 }
00194 write_char(out, 'e');
00195 break;
00196 default:
00197
00198 break;
00199 }
00200 }
00201
00202 template<class InIt>
00203 void bdecode_recursive(InIt& in, InIt end, entry& ret)
00204 {
00205 if (in == end) throw invalid_encoding();
00206 switch (*in)
00207 {
00208
00209
00210
00211 case 'i':
00212 {
00213 ++in;
00214 std::string val = read_until(in, end, 'e');
00215 assert(*in == 'e');
00216 ++in;
00217 ret = entry(entry::int_t);
00218 ret.integer() = boost::lexical_cast<entry::integer_type>(val);
00219 } break;
00220
00221
00222
00223 case 'l':
00224 {
00225 ret = entry(entry::list_t);
00226 ++in;
00227 while (*in != 'e')
00228 {
00229 ret.list().push_back(entry());
00230 entry& e = ret.list().back();
00231 bdecode_recursive(in, end, e);
00232 if (in == end) throw invalid_encoding();
00233 }
00234 assert(*in == 'e');
00235 ++in;
00236 } break;
00237
00238
00239
00240 case 'd':
00241 {
00242 ret = entry(entry::dictionary_t);
00243 ++in;
00244 while (*in != 'e')
00245 {
00246 entry key;
00247 bdecode_recursive(in, end, key);
00248 entry& e = ret[key.string()];
00249 bdecode_recursive(in, end, e);
00250 if (in == end) throw invalid_encoding();
00251 }
00252 assert(*in == 'e');
00253 ++in;
00254 } break;
00255
00256
00257
00258 default:
00259 if (isdigit((unsigned char)*in))
00260 {
00261 std::string len_s = read_until(in, end, ':');
00262 assert(*in == ':');
00263 ++in;
00264 int len = std::atoi(len_s.c_str());
00265 ret = entry(entry::string_t);
00266 read_string(in, end, len, ret.string());
00267 }
00268 else
00269 {
00270 throw invalid_encoding();
00271 }
00272 }
00273 }
00274 }
00275
00276 template<class OutIt>
00277 void bencode(OutIt out, const entry& e)
00278 {
00279 detail::bencode_recursive(out, e);
00280 }
00281
00282 template<class InIt>
00283 entry bdecode(InIt start, InIt end)
00284 {
00285 try
00286 {
00287 entry e;
00288 detail::bdecode_recursive(start, end, e);
00289 return e;
00290 }
00291 catch(type_error&)
00292 {
00293 throw invalid_encoding();
00294 }
00295 }
00296
00297 }
00298
00299 #endif // TORRENT_BENCODE_HPP_INCLUDED