From baf8e080125614326ba9c96ca8f2404fd12b050e Mon Sep 17 00:00:00 2001 From: jvoisin Date: Tue, 16 Aug 2011 15:31:30 +0200 Subject: Organise lib as modules (tarfile and bencode) --- lib/bencode/bencode.py | 142 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 lib/bencode/bencode.py (limited to 'lib/bencode/bencode.py') diff --git a/lib/bencode/bencode.py b/lib/bencode/bencode.py new file mode 100644 index 0000000..4acf788 --- /dev/null +++ b/lib/bencode/bencode.py @@ -0,0 +1,142 @@ +# The contents of this file are subject to the BitTorrent Open Source License +# Version 1.1 (the License). You may not copy or use this file, in either +# source code or executable form, except in compliance with the License. You +# may obtain a copy of the License at http://www.bittorrent.com/license/. +# +# Software distributed under the License is distributed on an AS IS basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. + +# Written by Petru Paler +# Modified by Julien (jvoisin) Voisin + +''' + A quick (and also nice) lib to bencode/bdecode torrent files +''' + + +import types + + +class BTFailure(Exception): + '''Custom Exception''' + pass + + +class Bencached(object): + '''Custom type : cached string''' + __slots__ = ['bencoded'] + + def __init__(self, string): + self.bencoded = string + + +def decode_int(x, f): + '''decode an int''' + f += 1 + newf = x.index('e', f) + n = int(x[f:newf]) + if x[f] == '-': + if x[f + 1] == '0': + raise ValueError + elif x[f] == '0' and newf != f + 1: + raise ValueError + return (n, newf + 1) + + +def decode_string(x, f): + '''decode a string''' + colon = x.index(':', f) + n = int(x[f:colon]) + if x[f] == '0' and colon != f + 1: + raise ValueError + colon += 1 + return (x[colon:colon + n], colon + n) + + +def decode_list(x, f): + '''decode a list''' + result = [] + f += 1 + while x[f] != 'e': + v, f = DECODE_FUNC[x[f]](x, f) + result.append(v) + return (result, f + 1) + + +def decode_dict(x, f): + '''decode a dict''' + result = {} + f += 1 + while x[f] != 'e': + k, f = decode_string(x, f) + result[k], f = DECODE_FUNC[x[f]](x, f) + return (result, f + 1) + + +def encode_bool(x, r): + '''bencode a boolean''' + if x: + encode_int(1, r) + else: + encode_int(0, r) + + +def encode_int(x, r): + '''bencode an integer/float''' + r.extend(('i', str(x), 'e')) + + +def encode_list(x, r): + '''bencode a list/tuple''' + r.append('l') + [ENCODE_FUNC[type(item)](item, r) for item in x] + r.append('e') + + +def encode_dict(x, result): + '''bencode a dict''' + result.append('d') + ilist = x.items() + ilist.sort() + for k, v in ilist: + result.extend((str(len(k)), ':', k)) + ENCODE_FUNC[type(v)](v, result) + result.append('e') + + +DECODE_FUNC = {} +DECODE_FUNC.update(dict([(str(x), decode_string) for x in xrange(9)])) +DECODE_FUNC['l'] = decode_list +DECODE_FUNC['d'] = decode_dict +DECODE_FUNC['i'] = decode_int + + +ENCODE_FUNC = {} +ENCODE_FUNC[Bencached] = lambda x, r: r.append(x.bencoded) +ENCODE_FUNC[types.IntType] = encode_int +ENCODE_FUNC[types.LongType] = encode_int +ENCODE_FUNC[types.StringType] = lambda x, r: r.extend((str(len(x)), ':', x)) +ENCODE_FUNC[types.ListType] = encode_list +ENCODE_FUNC[types.TupleType] = encode_list +ENCODE_FUNC[types.DictType] = encode_dict +ENCODE_FUNC[types.BooleanType] = encode_bool + + +def bencode(string): + '''bencode $string''' + table = [] + ENCODE_FUNC[type(string)](string, table) + return ''.join(table) + + +def bdecode(string): + '''decode $string''' + try: + result, lenght = DECODE_FUNC[string[0]](string, 0) + except (IndexError, KeyError, ValueError): + raise BTFailure('Not a valid bencoded string') + if lenght != len(string): + raise BTFailure('Invalid bencoded value (data after valid prefix)') + return result -- cgit v1.3