summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorjvoisin2011-08-15 00:56:07 +0200
committerjvoisin2011-08-15 00:56:07 +0200
commitcac28113963b131d4cb16382a7839608804f87d6 (patch)
tree59ec9c381f65fbf226035c8aa8c8416188d66ff8 /lib
parentffaf119905d3f2bea5ca6fca7c1ec092be407aa7 (diff)
Err, forgot to add the torrent lib, sorry :/
Diffstat (limited to 'lib')
-rw-r--r--lib/bencode.py142
1 files changed, 142 insertions, 0 deletions
diff --git a/lib/bencode.py b/lib/bencode.py
new file mode 100644
index 0000000..4acf788
--- /dev/null
+++ b/lib/bencode.py
@@ -0,0 +1,142 @@
1# The contents of this file are subject to the BitTorrent Open Source License
2# Version 1.1 (the License). You may not copy or use this file, in either
3# source code or executable form, except in compliance with the License. You
4# may obtain a copy of the License at http://www.bittorrent.com/license/.
5#
6# Software distributed under the License is distributed on an AS IS basis,
7# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
8# for the specific language governing rights and limitations under the
9# License.
10
11# Written by Petru Paler
12# Modified by Julien (jvoisin) Voisin
13
14'''
15 A quick (and also nice) lib to bencode/bdecode torrent files
16'''
17
18
19import types
20
21
22class BTFailure(Exception):
23 '''Custom Exception'''
24 pass
25
26
27class Bencached(object):
28 '''Custom type : cached string'''
29 __slots__ = ['bencoded']
30
31 def __init__(self, string):
32 self.bencoded = string
33
34
35def decode_int(x, f):
36 '''decode an int'''
37 f += 1
38 newf = x.index('e', f)
39 n = int(x[f:newf])
40 if x[f] == '-':
41 if x[f + 1] == '0':
42 raise ValueError
43 elif x[f] == '0' and newf != f + 1:
44 raise ValueError
45 return (n, newf + 1)
46
47
48def decode_string(x, f):
49 '''decode a string'''
50 colon = x.index(':', f)
51 n = int(x[f:colon])
52 if x[f] == '0' and colon != f + 1:
53 raise ValueError
54 colon += 1
55 return (x[colon:colon + n], colon + n)
56
57
58def decode_list(x, f):
59 '''decode a list'''
60 result = []
61 f += 1
62 while x[f] != 'e':
63 v, f = DECODE_FUNC[x[f]](x, f)
64 result.append(v)
65 return (result, f + 1)
66
67
68def decode_dict(x, f):
69 '''decode a dict'''
70 result = {}
71 f += 1
72 while x[f] != 'e':
73 k, f = decode_string(x, f)
74 result[k], f = DECODE_FUNC[x[f]](x, f)
75 return (result, f + 1)
76
77
78def encode_bool(x, r):
79 '''bencode a boolean'''
80 if x:
81 encode_int(1, r)
82 else:
83 encode_int(0, r)
84
85
86def encode_int(x, r):
87 '''bencode an integer/float'''
88 r.extend(('i', str(x), 'e'))
89
90
91def encode_list(x, r):
92 '''bencode a list/tuple'''
93 r.append('l')
94 [ENCODE_FUNC[type(item)](item, r) for item in x]
95 r.append('e')
96
97
98def encode_dict(x, result):
99 '''bencode a dict'''
100 result.append('d')
101 ilist = x.items()
102 ilist.sort()
103 for k, v in ilist:
104 result.extend((str(len(k)), ':', k))
105 ENCODE_FUNC[type(v)](v, result)
106 result.append('e')
107
108
109DECODE_FUNC = {}
110DECODE_FUNC.update(dict([(str(x), decode_string) for x in xrange(9)]))
111DECODE_FUNC['l'] = decode_list
112DECODE_FUNC['d'] = decode_dict
113DECODE_FUNC['i'] = decode_int
114
115
116ENCODE_FUNC = {}
117ENCODE_FUNC[Bencached] = lambda x, r: r.append(x.bencoded)
118ENCODE_FUNC[types.IntType] = encode_int
119ENCODE_FUNC[types.LongType] = encode_int
120ENCODE_FUNC[types.StringType] = lambda x, r: r.extend((str(len(x)), ':', x))
121ENCODE_FUNC[types.ListType] = encode_list
122ENCODE_FUNC[types.TupleType] = encode_list
123ENCODE_FUNC[types.DictType] = encode_dict
124ENCODE_FUNC[types.BooleanType] = encode_bool
125
126
127def bencode(string):
128 '''bencode $string'''
129 table = []
130 ENCODE_FUNC[type(string)](string, table)
131 return ''.join(table)
132
133
134def bdecode(string):
135 '''decode $string'''
136 try:
137 result, lenght = DECODE_FUNC[string[0]](string, 0)
138 except (IndexError, KeyError, ValueError):
139 raise BTFailure('Not a valid bencoded string')
140 if lenght != len(string):
141 raise BTFailure('Invalid bencoded value (data after valid prefix)')
142 return result