Skip to content

Commit 1560f8c

Browse files
committed
first commit
1 parent b930769 commit 1560f8c

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

.travis.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
language: python
2+
3+
python:
4+
- 2.6
5+
- 2.7
6+
- 3.3
7+
- 3.4
8+
- 3.5
9+
- pypy
10+
11+
before_install: pip install Cython
12+
install: python setup.py install
13+
script: coverage run --source=bencoder setup.py -q nosetests
14+
after_success: coveralls

bencoder.pyx

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#cython: language_level=3
2+
3+
# The contents of this file are subject to the BitTorrent Open Source License
4+
# Version 1.1 (the License). You may not copy or use this file, in either
5+
# source code or executable form, except in compliance with the License. You
6+
# may obtain a copy of the License at http://www.bittorrent.com/license/.
7+
#
8+
# Software distributed under the License is distributed on an AS IS basis,
9+
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10+
# for the specific language governing rights and limitations under the
11+
# License.
12+
13+
# Based on https://github.com/karamanolev/bencode3/blob/master/bencode.py
14+
15+
class BTFailure(Exception):
16+
pass
17+
18+
19+
def decode_int(bytes x, int f):
20+
f += 1
21+
new_f = x.index(b'e', f)
22+
n = int(x[f:new_f])
23+
if x[f] == ord('-'):
24+
if x[f + 1] == ord('0'):
25+
raise ValueError()
26+
elif x[f] == ord('0') and new_f != f + 1:
27+
raise ValueError()
28+
return n, new_f + 1
29+
30+
31+
def decode_string(bytes x, int f):
32+
colon = x.index(b':', f)
33+
n = int(x[f:colon])
34+
if x[f] == ord('0') and colon != f + 1:
35+
raise ValueError()
36+
colon += 1
37+
return x[colon:colon + n], colon + n
38+
39+
40+
def decode_list(bytes x, int f):
41+
r, f = [], f + 1
42+
while x[f] != ord('e'):
43+
v, f = decode_func[x[f]](x, f)
44+
r.append(v)
45+
return r, f + 1
46+
47+
48+
def decode_dict(bytes x, int f):
49+
r, f = {}, f + 1
50+
while x[f] != ord('e'):
51+
k, f = decode_string(x, f)
52+
r[k], f = decode_func[x[f]](x, f)
53+
return r, f + 1
54+
55+
56+
decode_func = {
57+
ord('l'): decode_list,
58+
ord('d'): decode_dict,
59+
ord('i'): decode_int,
60+
ord('1'): decode_string,
61+
ord('2'): decode_string,
62+
ord('0'): decode_string,
63+
ord('3'): decode_string,
64+
ord('4'): decode_string,
65+
ord('5'): decode_string,
66+
ord('6'): decode_string,
67+
ord('7'): decode_string,
68+
ord('8'): decode_string,
69+
ord('9'): decode_string,
70+
}
71+
72+
73+
def bdecode(bytes x):
74+
try:
75+
r, l = decode_func[x[0]](x, 0)
76+
except (IndexError, KeyError, ValueError):
77+
raise BTFailure("not a valid bencoded string")
78+
if l != len(x):
79+
raise BTFailure("invalid bencoded value (data after valid prefix)")
80+
return r
81+
82+
83+
def encode_int(int x, list r):
84+
r.extend((b'i', str(x).encode(), b'e'))
85+
86+
87+
def encode_bool(x, list r):
88+
if x:
89+
encode_int(1, r)
90+
else:
91+
encode_int(0, r)
92+
93+
94+
def encode_string(x, list r):
95+
if isinstance(x, str):
96+
x = x.encode()
97+
r.extend((str(len(x)).encode(), b':', x))
98+
99+
100+
def encode_list(x, list r):
101+
r.append(b'l')
102+
for i in x:
103+
encode_func[type(i)](i, r)
104+
r.append(b'e')
105+
106+
107+
def encode_dict(dict x, list r):
108+
r.append(b'd')
109+
item_list = list(x.items())
110+
item_list.sort()
111+
for k, v in item_list:
112+
if isinstance(k, str):
113+
k = k.encode()
114+
r.extend((str(len(k)).encode(), b':', k))
115+
encode_func[type(v)](v, r)
116+
r.append(b'e')
117+
118+
119+
encode_func = {
120+
int: encode_int,
121+
bytes: encode_string,
122+
str: encode_string,
123+
list: encode_list,
124+
tuple: encode_list,
125+
dict: encode_dict,
126+
bool: encode_bool,
127+
}
128+
129+
130+
def bencode(x):
131+
r = []
132+
encode_func[type(x)](x, r)
133+
return b''.join(r)

setup.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import sys
2+
3+
from setuptools import setup
4+
from setuptools.extension import Extension
5+
from setuptools.dist import Distribution
6+
Distribution(dict(setup_requires='Cython'))
7+
8+
try:
9+
from Cython.Distutils import build_ext
10+
except ImportError:
11+
print("Could not import Cython.Distutils. Install `cython` and rerun.")
12+
sys.exit(1)
13+
14+
ext_modules = [Extension("bencoder", ["bencoder.pyx"])]
15+
16+
setup(
17+
name='bencoder.pyx',
18+
version='1.0',
19+
description='Yet another bencode implementation in Cython',
20+
long_description="""""",
21+
author='whtsky',
22+
author_email='whtsky@gmail.com',
23+
url='https://github.com/whtsky/bencoder.pyx',
24+
license="BSDv3",
25+
platforms=['POSIX', 'Windows'],
26+
keywords=['bencoding', 'encode', 'decode', 'bittorrent'],
27+
classifiers=[
28+
"Environment :: Other Environment",
29+
"Intended Audience :: Developers",
30+
"Operating System :: OS Independent",
31+
"Programming Language :: Python :: 2",
32+
"Programming Language :: Python :: 3",
33+
"Topic :: Software Development :: Libraries :: Python Modules",
34+
],
35+
cmdclass={'build_ext': build_ext},
36+
ext_modules=ext_modules,
37+
setup_requires=['Cython'],
38+
tests_require=['nose'],
39+
test_suite='nose.collector',
40+
)

0 commit comments

Comments
 (0)