diff --git a/bencode.py b/bencode.py index c5c5d60..3a64056 100644 --- a/bencode.py +++ b/bencode.py @@ -28,7 +28,6 @@ # Software. -from types import IntType, LongType, StringType, ListType, TupleType, DictType try: from types import BooleanType except ImportError: @@ -37,29 +36,23 @@ try: from types import UnicodeType except ImportError: UnicodeType = None -from cStringIO import StringIO +from io import StringIO def decode_int(x, f): f += 1 - newf = x.index('e', f) - try: - n = int(x[f:newf]) - except: - n = long(x[f:newf]) - if x[f] == '-': - if x[f + 1] == '0': + newf = x.index(b'e', f) + n = int(x[f:newf]) + if x[f] == b'-'[0]: + if x[f + 1] == b'0'[0]: raise ValueError - elif x[f] == '0' and newf != f+1: + elif x[f] == b'0'[0] and newf != f+1: raise ValueError return (n, newf+1) - + def decode_string(x, f): - colon = x.index(':', f) - try: - n = int(x[f:colon]) - except (OverflowError, ValueError): - n = long(x[f:colon]) - if x[f] == '0' and colon != f+1: + colon = x.index(b':', f) + n = int(x[f:colon]) + if x[f] == b'0'[0] and colon != f+1: raise ValueError colon += 1 return (x[colon:colon+n], colon+n) @@ -70,15 +63,15 @@ def decode_unicode(x, f): def decode_list(x, f): r, f = [], f+1 - while x[f] != 'e': + while x[f] != b'e'[0]: v, f = decode_func[x[f]](x, f) r.append(v) return (r, f + 1) def decode_dict(x, f): r, f = {}, f+1 - lastkey = None - while x[f] != 'e': + lastkey = b'' + while x[f] != b'e'[0]: k, f = decode_string(x, f) if lastkey >= k: raise ValueError @@ -87,58 +80,63 @@ def decode_dict(x, f): return (r, f + 1) decode_func = {} -decode_func['l'] = decode_list -decode_func['d'] = decode_dict -decode_func['i'] = decode_int -decode_func['0'] = decode_string -decode_func['1'] = decode_string -decode_func['2'] = decode_string -decode_func['3'] = decode_string -decode_func['4'] = decode_string -decode_func['5'] = decode_string -decode_func['6'] = decode_string -decode_func['7'] = decode_string -decode_func['8'] = decode_string -decode_func['9'] = decode_string -#decode_func['u'] = decode_unicode - +decode_func[b'l'[0]] = decode_list +decode_func[b'd'[0]] = decode_dict +decode_func[b'i'[0]] = decode_int +decode_func[b'0'[0]] = decode_string +decode_func[b'1'[0]] = decode_string +decode_func[b'2'[0]] = decode_string +decode_func[b'3'[0]] = decode_string +decode_func[b'4'[0]] = decode_string +decode_func[b'5'[0]] = decode_string +decode_func[b'6'[0]] = decode_string +decode_func[b'7'[0]] = decode_string +decode_func[b'8'[0]] = decode_string +decode_func[b'9'[0]] = decode_string +#decode_func['u'[0]] = decode_unicode + def bdecode(x, sloppy = 0): try: r, l = decode_func[x[0]](x, 0) # except (IndexError, KeyError): except (IndexError, KeyError, ValueError): - raise ValueError, "bad bencoded data" + raise ValueError("bad bencoded data") if not sloppy and l != len(x): - raise ValueError, "bad bencoded data" + raise ValueError("bad bencoded data") return r def test_bdecode(): try: - bdecode('0:0:') + bdecode(b'0:0:') + assert 0 + except ValueError: + pass + try: + bdecode(b'ie') assert 0 except ValueError: pass try: - bdecode('ie') + bdecode(b'i341foo382e') assert 0 except ValueError: pass + assert bdecode(b'i4e') == 4 + assert bdecode(b'i0e') == 0 + assert bdecode(b'i123456789e') == 123456789 + assert bdecode(b'i-10e') == -10 try: - bdecode('i341foo382e') + bdecode(b'i-0e') 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') + bdecode(b'i123') assert 0 except ValueError: pass try: - bdecode('i123') + bdecode(b'') assert 0 except ValueError: pass @@ -148,108 +146,108 @@ def test_bdecode(): except ValueError: pass try: - bdecode('i6easd') + bdecode(b'i6easd') assert 0 except ValueError: pass try: - bdecode('35208734823ljdahflajhdf') + bdecode(b'35208734823ljdahflajhdf') assert 0 except ValueError: pass try: - bdecode('2:abfdjslhfld') + bdecode(b'2:abfdjslhfld') assert 0 except ValueError: pass - assert bdecode('0:') == '' - assert bdecode('3:abc') == 'abc' - assert bdecode('10:1234567890') == '1234567890' + assert bdecode(b'0:') == b'' + assert bdecode(b'3:abc') == b'abc' + assert bdecode(b'10:1234567890') == b'1234567890' try: - bdecode('02:xy') + bdecode(b'02:xy') assert 0 except ValueError: pass try: - bdecode('l') + bdecode(b'l') assert 0 except ValueError: pass - assert bdecode('le') == [] + assert bdecode(b'le') == [] try: - bdecode('leanfdldjfh') + bdecode(b'leanfdldjfh') assert 0 except ValueError: pass - assert bdecode('l0:0:0:e') == ['', '', ''] + assert bdecode(b'l0:0:0:e') == [b'', b'', b''] try: - bdecode('relwjhrlewjh') + bdecode(b'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]] + assert bdecode(b'li1ei2ei3ee') == [1, 2, 3] + assert bdecode(b'l3:asd2:xye') == [b'asd', b'xy'] + assert bdecode(b'll5:Alice3:Bobeli2ei3eee') == [[b'Alice', b'Bob'], [2, 3]] try: - bdecode('d') + bdecode(b'd') assert 0 except ValueError: pass try: - bdecode('defoobar') + bdecode(b'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}} + assert bdecode(b'de') == {} + assert bdecode(b'd3:agei25e4:eyes4:bluee') == {b'age': 25, b'eyes': b'blue'} + assert bdecode(b'd8:spam.mp3d6:author5:Alice6:lengthi100000eee') == {b'spam.mp3': {b'author': b'Alice', b'length': 100000}} try: - bdecode('d3:fooe') + bdecode(b'd3:fooe') assert 0 except ValueError: pass try: - bdecode('di1e0:e') + bdecode(b'di1e0:e') assert 0 except ValueError: pass try: - bdecode('d1:b0:1:a0:e') + bdecode(b'd1:b0:1:a0:e') assert 0 except ValueError: pass try: - bdecode('d1:a0:1:a0:e') + bdecode(b'd1:a0:1:a0:e') assert 0 except ValueError: pass try: - bdecode('i03e') + bdecode(b'i03e') assert 0 except ValueError: pass try: - bdecode('l01:ae') + bdecode(b'l01:ae') assert 0 except ValueError: pass try: - bdecode('9999:x') + bdecode(b'9999:x') assert 0 except ValueError: pass try: - bdecode('l0:') + bdecode(b'l0:') assert 0 except ValueError: pass try: - bdecode('d0:0:') + bdecode(b'd0:0:') assert 0 except ValueError: pass try: - bdecode('d0:') + bdecode(b'd0:') assert 0 except ValueError: pass @@ -261,83 +259,79 @@ class Bencached: self.marker = bencached_marker self.bencoded = s -BencachedType = type(Bencached('')) # insufficient, but good as a filter +BencachedType = type(Bencached(b'')) # insufficient, but good as a filter def encode_bencached(x,r): assert x.marker == bencached_marker r.append(x.bencoded) def encode_int(x,r): - r.extend(('i',str(x),'e')) + r.append(b'i%de' % x) def encode_bool(x,r): encode_int(int(x),r) -def encode_string(x,r): - r.extend((str(len(x)),':',x)) +def encode_bytes(x,r): + r.extend((b'%d:' % len(x),x)) -def encode_unicode(x,r): +def encode_string(x,r): #r.append('u') - encode_string(x.encode('UTF-8'),r) + encode_bytes(x.encode('UTF-8'),r) def encode_list(x,r): - r.append('l') + r.append(b'l') for e in x: encode_func[type(e)](e, r) - r.append('e') + r.append(b'e') def encode_dict(x,r): - r.append('d') - ilist = x.items() - ilist.sort() - for k,v in ilist: - r.extend((str(len(k)),':',k)) + r.append(b'd') + for k,v in sorted(x.items()): + r.extend((b'%d:' % len(k),k.encode('UTF-8'))) encode_func[type(v)](v, r) - r.append('e') + r.append(b'e') encode_func = {} encode_func[BencachedType] = encode_bencached -encode_func[IntType] = encode_int -encode_func[LongType] = encode_int -encode_func[StringType] = encode_string -encode_func[ListType] = encode_list -encode_func[TupleType] = encode_list -encode_func[DictType] = encode_dict +encode_func[int] = encode_int +encode_func[str] = encode_string +encode_func[list] = encode_list +encode_func[tuple] = encode_list +encode_func[type({})] = encode_dict if BooleanType: encode_func[BooleanType] = encode_bool if UnicodeType: encode_func[UnicodeType] = encode_unicode - + def bencode(x): r = [] try: encode_func[type(x)](x, r) except: - print "*** error *** could not encode type %s (value: %s)" % (type(x), x) - assert 0 - return ''.join(r) + raise ValueError("could not encode type %s (value: %s)" % (type(x), x)) + return b''.join(r) 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' + assert bencode(4) == b'i4e' + assert bencode(0) == b'i0e' + assert bencode(-10) == b'i-10e' + assert bencode(12345678901234567890) == b'i12345678901234567890e' + assert bencode('') == b'0:' + assert bencode('abc') == b'3:abc' + assert bencode('1234567890') == b'10:1234567890' + assert bencode([]) == b'le' + assert bencode([1, 2, 3]) == b'li1ei2ei3ee' + assert bencode([['Alice', 'Bob'], [2, 3]]) == b'll5:Alice3:Bobeli2ei3eee' + assert bencode({}) == b'de' + assert bencode({'age': 25, 'eyes': 'blue'}) == b'd3:agei25e4:eyes4:bluee' + assert bencode({'spam.mp3': {'author': 'Alice', 'length': 100000}}) == b'd8:spam.mp3d6:author5:Alice6:lengthi100000eee' try: bencode({1: 'foo'}) assert 0 - except AssertionError: + except (ValueError, AssertionError): pass - + try: import psyco psyco.bind(bdecode)