X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=bencode.py;fp=bencode.py;h=93af40744a6365578f7aa4b1589a98c451fe49f4;hb=32f5f5669ceb11c4c951ed9bc9cd0f992b15817d;hp=0000000000000000000000000000000000000000;hpb=e9780a41991139e0ff86eeffa9279a4d8379cd22;p=quix0rs-apt-p2p.git diff --git a/bencode.py b/bencode.py new file mode 100644 index 0000000..93af407 --- /dev/null +++ b/bencode.py @@ -0,0 +1,254 @@ +# Written by Petru Paler +# see LICENSE.txt for license information + +from types import IntType, LongType, StringType, ListType, TupleType, DictType +import re +from cStringIO import StringIO + +int_filter = re.compile('(0|-?[1-9][0-9]*)e') + +def decode_int(x, f): + m = int_filter.match(x, f) + if m is None: + raise ValueError + return (long(m.group(1)), m.end()) + +string_filter = re.compile('(0|[1-9][0-9]*):') + +def decode_string(x, f): + m = string_filter.match(x, f) + if m is None: + raise ValueError + l = int(m.group(1)) + s = m.end() + return (x[s:s+l], s + l) + +def decode_list(x, f): + r = [] + while x[f] != 'e': + v, f = bdecode_rec(x, f) + r.append(v) + return (r, f + 1) + +def decode_dict(x, f): + r = {} + lastkey = None + while x[f] != 'e': + k, f = decode_string(x, f) + if lastkey is not None and lastkey >= k: + raise ValueError + lastkey = k + v, f = bdecode_rec(x, f) + r[k] = v + return (r, f + 1) + +def bdecode_rec(x, f): + t = x[f] + if t == 'i': + return decode_int(x, f + 1) + elif t == 'l': + return decode_list(x, f + 1) + elif t == 'd': + return decode_dict(x, f + 1) + else: + return decode_string(x, f) + +def bdecode(x): + try: + r, l = bdecode_rec(x, 0) + except IndexError: + raise ValueError + if l != len(x): + raise ValueError + return r + +def test_bdecode(): + try: + bdecode('0:0:') + assert 0 + except ValueError: + pass + try: + bdecode('ie') + assert 0 + except ValueError: + pass + try: + bdecode('i341foo382e') + assert 0 + except ValueError: + pass + assert bdecode('i4e') == 4L + assert bdecode('i0e') == 0L + assert bdecode('i123456789e') == 123456789L + assert bdecode('i-10e') == -10L + try: + bdecode('i-0e') + assert 0 + except ValueError: + pass + try: + bdecode('i123') + assert 0 + except ValueError: + pass + try: + bdecode('') + assert 0 + except ValueError: + pass + try: + bdecode('i6easd') + assert 0 + except ValueError: + pass + try: + bdecode('35208734823ljdahflajhdf') + assert 0 + except ValueError: + pass + try: + bdecode('2:abfdjslhfld') + assert 0 + except ValueError: + pass + assert bdecode('0:') == '' + assert bdecode('3:abc') == 'abc' + assert bdecode('10:1234567890') == '1234567890' + try: + bdecode('02:xy') + assert 0 + except ValueError: + pass + try: + bdecode('l') + assert 0 + except ValueError: + pass + assert bdecode('le') == [] + try: + bdecode('leanfdldjfh') + assert 0 + except ValueError: + pass + assert bdecode('l0:0:0:e') == ['', '', ''] + try: + bdecode('relwjhrlewjh') + assert 0 + except ValueError: + pass + assert bdecode('li1ei2ei3ee') == [1, 2, 3] + assert bdecode('l3:asd2:xye') == ['asd', 'xy'] + assert bdecode('ll5:Alice3:Bobeli2ei3eee') == [['Alice', 'Bob'], [2, 3]] + try: + bdecode('d') + assert 0 + except ValueError: + pass + try: + bdecode('defoobar') + assert 0 + except ValueError: + pass + assert bdecode('de') == {} + assert bdecode('d3:agei25e4:eyes4:bluee') == {'age': 25, 'eyes': 'blue'} + assert bdecode('d8:spam.mp3d6:author5:Alice6:lengthi100000eee') == {'spam.mp3': {'author': 'Alice', 'length': 100000}} + try: + bdecode('d3:fooe') + assert 0 + except ValueError: + pass + try: + bdecode('di1e0:e') + assert 0 + except ValueError: + pass + try: + bdecode('d1:b0:1:a0:e') + assert 0 + except ValueError: + pass + try: + bdecode('d1:a0:1:a0:e') + assert 0 + except ValueError: + pass + try: + bdecode('i03e') + assert 0 + except ValueError: + pass + try: + bdecode('l01:ae') + assert 0 + except ValueError: + pass + try: + bdecode('9999:x') + assert 0 + except ValueError: + pass + try: + bdecode('l0:') + assert 0 + except ValueError: + pass + try: + bdecode('d0:0:') + assert 0 + except ValueError: + pass + try: + bdecode('d0:') + assert 0 + except ValueError: + pass + +def bencode_rec(x, b): + t = type(x) + if t in (IntType, LongType): + b.write('i%de' % x) + elif t is StringType: + b.write('%d:%s' % (len(x), x)) + elif t in (ListType, TupleType): + b.write('l') + for e in x: + bencode_rec(e, b) + b.write('e') + elif t is DictType: + b.write('d') + keylist = x.keys() + keylist.sort() + for k in keylist: + assert type(k) is StringType + bencode_rec(k, b) + bencode_rec(x[k], b) + b.write('e') + else: + assert 0 + +def bencode(x): + b = StringIO() + bencode_rec(x, b) + return b.getvalue() + +def test_bencode(): + assert bencode(4) == 'i4e' + assert bencode(0) == 'i0e' + assert bencode(-10) == 'i-10e' + assert bencode(12345678901234567890L) == 'i12345678901234567890e' + assert bencode('') == '0:' + assert bencode('abc') == '3:abc' + assert bencode('1234567890') == '10:1234567890' + assert bencode([]) == 'le' + assert bencode([1, 2, 3]) == 'li1ei2ei3ee' + assert bencode([['Alice', 'Bob'], [2, 3]]) == 'll5:Alice3:Bobeli2ei3eee' + assert bencode({}) == 'de' + assert bencode({'age': 25, 'eyes': 'blue'}) == 'd3:agei25e4:eyes4:bluee' + assert bencode({'spam.mp3': {'author': 'Alice', 'length': 100000}}) == 'd8:spam.mp3d6:author5:Alice6:lengthi100000eee' + try: + bencode({1: 'foo'}) + assert 0 + except AssertionError: + pass +