diff --git a/ui/medashare/btv/bencode.py b/ui/medashare/btv/bencode.py index 34a4115..7385947 100644 --- a/ui/medashare/btv/bencode.py +++ b/ui/medashare/btv/bencode.py @@ -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() diff --git a/ui/medashare/btv/fixtures/bittorrent-v2-test.torrent b/ui/medashare/btv/fixtures/bittorrent-v2-test.torrent new file mode 100644 index 0000000..8ad4c7e Binary files /dev/null and b/ui/medashare/btv/fixtures/bittorrent-v2-test.torrent differ