MetaData Sharing
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

341 lines
8.6 KiB

  1. # Written by Petru Paler, Uoti Urpala, Ross Cohen and John Hoffman
  2. # see LICENSE.txt for license information
  3. # LICENSE.txt:
  4. # Unless otherwise noted, all files are released under the MIT
  5. # license, exceptions contain licensing information in them.
  6. #
  7. # Copyright (C) 2001-2002 Bram Cohen
  8. #
  9. # Permission is hereby granted, free of charge, to any person
  10. # obtaining a copy of this software and associated documentation files
  11. # (the "Software"), to deal in the Software without restriction,
  12. # including without limitation the rights to use, copy, modify, merge,
  13. # publish, distribute, sublicense, and/or sell copies of the Software,
  14. # and to permit persons to whom the Software is furnished to do so,
  15. # subject to the following conditions:
  16. #
  17. # The above copyright notice and this permission notice shall be
  18. # included in all copies or substantial portions of the Software.
  19. #
  20. # The Software is provided "AS IS", without warranty of any kind,
  21. # express or implied, including but not limited to the warranties of
  22. # merchantability, fitness for a particular purpose and
  23. # noninfringement. In no event shall the authors or copyright holders
  24. # be liable for any claim, damages or other liability, whether in an
  25. # action of contract, tort or otherwise, arising from, out of or in
  26. # connection with the Software or the use or other dealings in the
  27. # Software.
  28. try:
  29. from types import BooleanType
  30. except ImportError:
  31. BooleanType = None
  32. try:
  33. from types import UnicodeType
  34. except ImportError:
  35. UnicodeType = None
  36. from io import StringIO
  37. def decode_int(x, f):
  38. f += 1
  39. newf = x.index(b'e', f)
  40. n = int(x[f:newf])
  41. if x[f] == b'-'[0]:
  42. if x[f + 1] == b'0'[0]:
  43. raise ValueError
  44. elif x[f] == b'0'[0] and newf != f+1:
  45. raise ValueError
  46. return (n, newf+1)
  47. def decode_string(x, f):
  48. colon = x.index(b':', f)
  49. n = int(x[f:colon])
  50. if x[f] == b'0'[0] and colon != f+1:
  51. raise ValueError
  52. colon += 1
  53. return (x[colon:colon+n], colon+n)
  54. def decode_unicode(x, f):
  55. s, f = decode_string(x, f+1)
  56. return (s.decode('UTF-8'),f)
  57. def decode_list(x, f):
  58. r, f = [], f+1
  59. while x[f] != b'e'[0]:
  60. v, f = decode_func[x[f]](x, f)
  61. r.append(v)
  62. return (r, f + 1)
  63. def decode_dict(x, f):
  64. r, f = {}, f+1
  65. lastkey = b''
  66. while x[f] != b'e'[0]:
  67. k, f = decode_string(x, f)
  68. if lastkey >= k:
  69. raise ValueError
  70. lastkey = k
  71. r[k], f = decode_func[x[f]](x, f)
  72. return (r, f + 1)
  73. decode_func = {}
  74. decode_func[b'l'[0]] = decode_list
  75. decode_func[b'd'[0]] = decode_dict
  76. decode_func[b'i'[0]] = decode_int
  77. decode_func[b'0'[0]] = decode_string
  78. decode_func[b'1'[0]] = decode_string
  79. decode_func[b'2'[0]] = decode_string
  80. decode_func[b'3'[0]] = decode_string
  81. decode_func[b'4'[0]] = decode_string
  82. decode_func[b'5'[0]] = decode_string
  83. decode_func[b'6'[0]] = decode_string
  84. decode_func[b'7'[0]] = decode_string
  85. decode_func[b'8'[0]] = decode_string
  86. decode_func[b'9'[0]] = decode_string
  87. #decode_func['u'[0]] = decode_unicode
  88. def bdecode(x, sloppy = 0):
  89. try:
  90. r, l = decode_func[x[0]](x, 0)
  91. # except (IndexError, KeyError):
  92. except (IndexError, KeyError, ValueError):
  93. raise ValueError("bad bencoded data")
  94. if not sloppy and l != len(x):
  95. raise ValueError("bad bencoded data")
  96. return r
  97. def test_bdecode():
  98. try:
  99. bdecode(b'0:0:')
  100. assert 0
  101. except ValueError:
  102. pass
  103. try:
  104. bdecode(b'ie')
  105. assert 0
  106. except ValueError:
  107. pass
  108. try:
  109. bdecode(b'i341foo382e')
  110. assert 0
  111. except ValueError:
  112. pass
  113. assert bdecode(b'i4e') == 4
  114. assert bdecode(b'i0e') == 0
  115. assert bdecode(b'i123456789e') == 123456789
  116. assert bdecode(b'i-10e') == -10
  117. try:
  118. bdecode(b'i-0e')
  119. assert 0
  120. except ValueError:
  121. pass
  122. try:
  123. bdecode(b'i123')
  124. assert 0
  125. except ValueError:
  126. pass
  127. try:
  128. bdecode(b'')
  129. assert 0
  130. except ValueError:
  131. pass
  132. try:
  133. bdecode('')
  134. assert 0
  135. except ValueError:
  136. pass
  137. try:
  138. bdecode(b'i6easd')
  139. assert 0
  140. except ValueError:
  141. pass
  142. try:
  143. bdecode(b'35208734823ljdahflajhdf')
  144. assert 0
  145. except ValueError:
  146. pass
  147. try:
  148. bdecode(b'2:abfdjslhfld')
  149. assert 0
  150. except ValueError:
  151. pass
  152. assert bdecode(b'0:') == b''
  153. assert bdecode(b'3:abc') == b'abc'
  154. assert bdecode(b'10:1234567890') == b'1234567890'
  155. try:
  156. bdecode(b'02:xy')
  157. assert 0
  158. except ValueError:
  159. pass
  160. try:
  161. bdecode(b'l')
  162. assert 0
  163. except ValueError:
  164. pass
  165. assert bdecode(b'le') == []
  166. try:
  167. bdecode(b'leanfdldjfh')
  168. assert 0
  169. except ValueError:
  170. pass
  171. assert bdecode(b'l0:0:0:e') == [b'', b'', b'']
  172. try:
  173. bdecode(b'relwjhrlewjh')
  174. assert 0
  175. except ValueError:
  176. pass
  177. assert bdecode(b'li1ei2ei3ee') == [1, 2, 3]
  178. assert bdecode(b'l3:asd2:xye') == [b'asd', b'xy']
  179. assert bdecode(b'll5:Alice3:Bobeli2ei3eee') == [[b'Alice', b'Bob'], [2, 3]]
  180. try:
  181. bdecode(b'd')
  182. assert 0
  183. except ValueError:
  184. pass
  185. try:
  186. bdecode(b'defoobar')
  187. assert 0
  188. except ValueError:
  189. pass
  190. assert bdecode(b'de') == {}
  191. assert bdecode(b'd3:agei25e4:eyes4:bluee') == {b'age': 25, b'eyes': b'blue'}
  192. assert bdecode(b'd8:spam.mp3d6:author5:Alice6:lengthi100000eee') == {b'spam.mp3': {b'author': b'Alice', b'length': 100000}}
  193. try:
  194. bdecode(b'd3:fooe')
  195. assert 0
  196. except ValueError:
  197. pass
  198. try:
  199. bdecode(b'di1e0:e')
  200. assert 0
  201. except ValueError:
  202. pass
  203. try:
  204. bdecode(b'd1:b0:1:a0:e')
  205. assert 0
  206. except ValueError:
  207. pass
  208. try:
  209. bdecode(b'd1:a0:1:a0:e')
  210. assert 0
  211. except ValueError:
  212. pass
  213. try:
  214. bdecode(b'i03e')
  215. assert 0
  216. except ValueError:
  217. pass
  218. try:
  219. bdecode(b'l01:ae')
  220. assert 0
  221. except ValueError:
  222. pass
  223. try:
  224. bdecode(b'9999:x')
  225. assert 0
  226. except ValueError:
  227. pass
  228. try:
  229. bdecode(b'l0:')
  230. assert 0
  231. except ValueError:
  232. pass
  233. try:
  234. bdecode(b'd0:0:')
  235. assert 0
  236. except ValueError:
  237. pass
  238. try:
  239. bdecode(b'd0:')
  240. assert 0
  241. except ValueError:
  242. pass
  243. bencached_marker = []
  244. class Bencached:
  245. def __init__(self, s):
  246. self.marker = bencached_marker
  247. self.bencoded = s
  248. BencachedType = type(Bencached(b'')) # insufficient, but good as a filter
  249. def encode_bencached(x,r):
  250. assert x.marker == bencached_marker
  251. r.append(x.bencoded)
  252. def encode_int(x,r):
  253. r.append(b'i%de' % x)
  254. def encode_bool(x,r):
  255. encode_int(int(x),r)
  256. def encode_bytes(x,r):
  257. r.extend((b'%d:' % len(x),x))
  258. def encode_string(x,r):
  259. #r.append('u')
  260. encode_bytes(x.encode('UTF-8'),r)
  261. def encode_list(x,r):
  262. r.append(b'l')
  263. for e in x:
  264. encode_func[type(e)](e, r)
  265. r.append(b'e')
  266. def encode_dict(x,r):
  267. r.append(b'd')
  268. for k,v in sorted(x.items()):
  269. r.extend((b'%d:' % len(k),k.encode('UTF-8')))
  270. encode_func[type(v)](v, r)
  271. r.append(b'e')
  272. encode_func = {}
  273. encode_func[BencachedType] = encode_bencached
  274. encode_func[int] = encode_int
  275. encode_func[str] = encode_string
  276. encode_func[list] = encode_list
  277. encode_func[tuple] = encode_list
  278. encode_func[type({})] = encode_dict
  279. if BooleanType:
  280. encode_func[BooleanType] = encode_bool
  281. if UnicodeType:
  282. encode_func[UnicodeType] = encode_unicode
  283. def bencode(x):
  284. r = []
  285. try:
  286. encode_func[type(x)](x, r)
  287. except:
  288. raise ValueError("could not encode type %s (value: %s)" % (type(x), x))
  289. return b''.join(r)
  290. def test_bencode():
  291. assert bencode(4) == b'i4e'
  292. assert bencode(0) == b'i0e'
  293. assert bencode(-10) == b'i-10e'
  294. assert bencode(12345678901234567890) == b'i12345678901234567890e'
  295. assert bencode('') == b'0:'
  296. assert bencode('abc') == b'3:abc'
  297. assert bencode('1234567890') == b'10:1234567890'
  298. assert bencode([]) == b'le'
  299. assert bencode([1, 2, 3]) == b'li1ei2ei3ee'
  300. assert bencode([['Alice', 'Bob'], [2, 3]]) == b'll5:Alice3:Bobeli2ei3eee'
  301. assert bencode({}) == b'de'
  302. assert bencode({'age': 25, 'eyes': 'blue'}) == b'd3:agei25e4:eyes4:bluee'
  303. assert bencode({'spam.mp3': {'author': 'Alice', 'length': 100000}}) == b'd8:spam.mp3d6:author5:Alice6:lengthi100000eee'
  304. try:
  305. bencode({1: 'foo'})
  306. assert 0
  307. except (ValueError, AssertionError):
  308. pass
  309. try:
  310. import psyco
  311. psyco.bind(bdecode)
  312. psyco.bind(bencode)
  313. except ImportError:
  314. pass