|
|
|
@@ -68,16 +68,23 @@ def decode_list(x, f): |
|
|
|
r.append(v) |
|
|
|
return (r, f + 1) |
|
|
|
|
|
|
|
def decode_dict(x, f): |
|
|
|
def decode_dict(x, f, parent=None): |
|
|
|
r, f = {}, f+1 |
|
|
|
lastkey = None |
|
|
|
while x[f] != b'e'[0]: |
|
|
|
k, f = decode_string(x, f) |
|
|
|
k = k.decode('us-ascii') |
|
|
|
if not parent or parent not in { 'piece layers' }: |
|
|
|
k = k.decode('us-ascii') |
|
|
|
if lastkey is not None and lastkey >= k: |
|
|
|
raise ValueError |
|
|
|
lastkey = k |
|
|
|
r[k], f = decode_func[x[f]](x, f) |
|
|
|
|
|
|
|
#decode value |
|
|
|
fun = decode_func[x[f]] |
|
|
|
kwargs = {} |
|
|
|
if fun is decode_dict: |
|
|
|
kwargs['parent'] = k |
|
|
|
r[k], f = fun(x, f, **kwargs) |
|
|
|
return (r, f + 1) |
|
|
|
|
|
|
|
decode_func = {} |
|
|
|
@@ -285,11 +292,18 @@ def encode_list(x,r): |
|
|
|
encode_func[type(e)](e, r) |
|
|
|
r.append(b'e') |
|
|
|
|
|
|
|
def encode_dict(x,r): |
|
|
|
def encode_dict(x,r, parent=None): |
|
|
|
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) |
|
|
|
origk = k |
|
|
|
if not parent or parent not in { 'piece layers' }: |
|
|
|
k = k.encode('us-ascii') |
|
|
|
r.extend((b'%d:' % len(k),k)) |
|
|
|
efun = encode_func[type(v)] |
|
|
|
kwargs = {} |
|
|
|
if efun is encode_dict: |
|
|
|
kwargs['parent'] = origk |
|
|
|
efun(v, r, **kwargs) |
|
|
|
r.append(b'e') |
|
|
|
|
|
|
|
encode_func = {} |
|
|
|
@@ -341,6 +355,17 @@ class _TestCases(unittest.TestCase): |
|
|
|
|
|
|
|
self.assertEqual(bencode({'': 5}), b'd0:i5ee') |
|
|
|
|
|
|
|
def test_round_trip_files(self): |
|
|
|
import importlib |
|
|
|
|
|
|
|
fixtures = importlib.resources.files(__name__[:__name__.rindex('.')]) / 'fixtures' |
|
|
|
|
|
|
|
for i in fixtures.iterdir(): |
|
|
|
with self.subTest(file=str(i)): |
|
|
|
data = i.read_bytes() |
|
|
|
|
|
|
|
self.assertEqual(data, bencode(bdecode(data))) |
|
|
|
|
|
|
|
def test_bdecode(self): |
|
|
|
test_bdecode() |
|
|
|
|
|
|
|
|