]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blob - www/pages/torrent/client/bencode.py
Change Color of Menuitem CeBIT.
[people/shoehn/ipfire.org.git] / www / pages / torrent / client / bencode.py
1 # Written by Petru Paler, Uoti Urpala, Ross Cohen and John Hoffman
2 # see LICENSE.txt for license information
3
4 from types import IntType, LongType, StringType, ListType, TupleType, DictType
5 try:
6 from types import BooleanType
7 except ImportError:
8 BooleanType = None
9 try:
10 from types import UnicodeType
11 except ImportError:
12 UnicodeType = None
13 from cStringIO import StringIO
14
15 def decode_int(x, f):
16 f += 1
17 newf = x.index('e', f)
18 try:
19 n = int(x[f:newf])
20 except:
21 n = long(x[f:newf])
22 if x[f] == '-':
23 if x[f + 1] == '0':
24 raise ValueError
25 elif x[f] == '0' and newf != f+1:
26 raise ValueError
27 return (n, newf+1)
28
29 def decode_string(x, f):
30 colon = x.index(':', f)
31 try:
32 n = int(x[f:colon])
33 except (OverflowError, ValueError):
34 n = long(x[f:colon])
35 if x[f] == '0' and colon != f+1:
36 raise ValueError
37 colon += 1
38 return (x[colon:colon+n], colon+n)
39
40 def decode_unicode(x, f):
41 s, f = decode_string(x, f+1)
42 return (s.decode('UTF-8'),f)
43
44 def decode_list(x, f):
45 r, f = [], f+1
46 while x[f] != 'e':
47 v, f = decode_func[x[f]](x, f)
48 r.append(v)
49 return (r, f + 1)
50
51 def decode_dict(x, f):
52 r, f = {}, f+1
53 lastkey = None
54 while x[f] != 'e':
55 k, f = decode_string(x, f)
56 if lastkey >= k:
57 raise ValueError
58 lastkey = k
59 r[k], f = decode_func[x[f]](x, f)
60 return (r, f + 1)
61
62 decode_func = {}
63 decode_func['l'] = decode_list
64 decode_func['d'] = decode_dict
65 decode_func['i'] = decode_int
66 decode_func['0'] = decode_string
67 decode_func['1'] = decode_string
68 decode_func['2'] = decode_string
69 decode_func['3'] = decode_string
70 decode_func['4'] = decode_string
71 decode_func['5'] = decode_string
72 decode_func['6'] = decode_string
73 decode_func['7'] = decode_string
74 decode_func['8'] = decode_string
75 decode_func['9'] = decode_string
76 #decode_func['u'] = decode_unicode
77
78 def bdecode(x, sloppy = 0):
79 try:
80 r, l = decode_func[x[0]](x, 0)
81 # except (IndexError, KeyError):
82 except (IndexError, KeyError, ValueError):
83 raise ValueError, "bad bencoded data"
84 if not sloppy and l != len(x):
85 raise ValueError, "bad bencoded data"
86 return r
87
88 def test_bdecode():
89 try:
90 bdecode('0:0:')
91 assert 0
92 except ValueError:
93 pass
94 try:
95 bdecode('ie')
96 assert 0
97 except ValueError:
98 pass
99 try:
100 bdecode('i341foo382e')
101 assert 0
102 except ValueError:
103 pass
104 assert bdecode('i4e') == 4L
105 assert bdecode('i0e') == 0L
106 assert bdecode('i123456789e') == 123456789L
107 assert bdecode('i-10e') == -10L
108 try:
109 bdecode('i-0e')
110 assert 0
111 except ValueError:
112 pass
113 try:
114 bdecode('i123')
115 assert 0
116 except ValueError:
117 pass
118 try:
119 bdecode('')
120 assert 0
121 except ValueError:
122 pass
123 try:
124 bdecode('i6easd')
125 assert 0
126 except ValueError:
127 pass
128 try:
129 bdecode('35208734823ljdahflajhdf')
130 assert 0
131 except ValueError:
132 pass
133 try:
134 bdecode('2:abfdjslhfld')
135 assert 0
136 except ValueError:
137 pass
138 assert bdecode('0:') == ''
139 assert bdecode('3:abc') == 'abc'
140 assert bdecode('10:1234567890') == '1234567890'
141 try:
142 bdecode('02:xy')
143 assert 0
144 except ValueError:
145 pass
146 try:
147 bdecode('l')
148 assert 0
149 except ValueError:
150 pass
151 assert bdecode('le') == []
152 try:
153 bdecode('leanfdldjfh')
154 assert 0
155 except ValueError:
156 pass
157 assert bdecode('l0:0:0:e') == ['', '', '']
158 try:
159 bdecode('relwjhrlewjh')
160 assert 0
161 except ValueError:
162 pass
163 assert bdecode('li1ei2ei3ee') == [1, 2, 3]
164 assert bdecode('l3:asd2:xye') == ['asd', 'xy']
165 assert bdecode('ll5:Alice3:Bobeli2ei3eee') == [['Alice', 'Bob'], [2, 3]]
166 try:
167 bdecode('d')
168 assert 0
169 except ValueError:
170 pass
171 try:
172 bdecode('defoobar')
173 assert 0
174 except ValueError:
175 pass
176 assert bdecode('de') == {}
177 assert bdecode('d3:agei25e4:eyes4:bluee') == {'age': 25, 'eyes': 'blue'}
178 assert bdecode('d8:spam.mp3d6:author5:Alice6:lengthi100000eee') == {'spam.mp3': {'author': 'Alice', 'length': 100000}}
179 try:
180 bdecode('d3:fooe')
181 assert 0
182 except ValueError:
183 pass
184 try:
185 bdecode('di1e0:e')
186 assert 0
187 except ValueError:
188 pass
189 try:
190 bdecode('d1:b0:1:a0:e')
191 assert 0
192 except ValueError:
193 pass
194 try:
195 bdecode('d1:a0:1:a0:e')
196 assert 0
197 except ValueError:
198 pass
199 try:
200 bdecode('i03e')
201 assert 0
202 except ValueError:
203 pass
204 try:
205 bdecode('l01:ae')
206 assert 0
207 except ValueError:
208 pass
209 try:
210 bdecode('9999:x')
211 assert 0
212 except ValueError:
213 pass
214 try:
215 bdecode('l0:')
216 assert 0
217 except ValueError:
218 pass
219 try:
220 bdecode('d0:0:')
221 assert 0
222 except ValueError:
223 pass
224 try:
225 bdecode('d0:')
226 assert 0
227 except ValueError:
228 pass
229
230 bencached_marker = []
231
232 class Bencached:
233 def __init__(self, s):
234 self.marker = bencached_marker
235 self.bencoded = s
236
237 BencachedType = type(Bencached('')) # insufficient, but good as a filter
238
239 def encode_bencached(x,r):
240 assert x.marker == bencached_marker
241 r.append(x.bencoded)
242
243 def encode_int(x,r):
244 r.extend(('i',str(x),'e'))
245
246 def encode_bool(x,r):
247 encode_int(int(x),r)
248
249 def encode_string(x,r):
250 r.extend((str(len(x)),':',x))
251
252 def encode_unicode(x,r):
253 #r.append('u')
254 encode_string(x.encode('UTF-8'),r)
255
256 def encode_list(x,r):
257 r.append('l')
258 for e in x:
259 encode_func[type(e)](e, r)
260 r.append('e')
261
262 def encode_dict(x,r):
263 r.append('d')
264 ilist = x.items()
265 ilist.sort()
266 for k,v in ilist:
267 r.extend((str(len(k)),':',k))
268 encode_func[type(v)](v, r)
269 r.append('e')
270
271 encode_func = {}
272 encode_func[BencachedType] = encode_bencached
273 encode_func[IntType] = encode_int
274 encode_func[LongType] = encode_int
275 encode_func[StringType] = encode_string
276 encode_func[ListType] = encode_list
277 encode_func[TupleType] = encode_list
278 encode_func[DictType] = encode_dict
279 if BooleanType:
280 encode_func[BooleanType] = encode_bool
281 if UnicodeType:
282 encode_func[UnicodeType] = encode_unicode
283
284 def bencode(x):
285 r = []
286 try:
287 encode_func[type(x)](x, r)
288 except:
289 print "*** error *** could not encode type %s (value: %s)" % (type(x), x)
290 assert 0
291 return ''.join(r)
292
293 def test_bencode():
294 assert bencode(4) == 'i4e'
295 assert bencode(0) == 'i0e'
296 assert bencode(-10) == 'i-10e'
297 assert bencode(12345678901234567890L) == 'i12345678901234567890e'
298 assert bencode('') == '0:'
299 assert bencode('abc') == '3:abc'
300 assert bencode('1234567890') == '10:1234567890'
301 assert bencode([]) == 'le'
302 assert bencode([1, 2, 3]) == 'li1ei2ei3ee'
303 assert bencode([['Alice', 'Bob'], [2, 3]]) == 'll5:Alice3:Bobeli2ei3eee'
304 assert bencode({}) == 'de'
305 assert bencode({'age': 25, 'eyes': 'blue'}) == 'd3:agei25e4:eyes4:bluee'
306 assert bencode({'spam.mp3': {'author': 'Alice', 'length': 100000}}) == 'd8:spam.mp3d6:author5:Alice6:lengthi100000eee'
307 try:
308 bencode({1: 'foo'})
309 assert 0
310 except AssertionError:
311 pass
312
313
314 try:
315 import psyco
316 psyco.bind(bdecode)
317 psyco.bind(bencode)
318 except ImportError:
319 pass