diff options
Diffstat (limited to 'MAT/bencode/bencode.py')
| -rw-r--r-- | MAT/bencode/bencode.py | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/MAT/bencode/bencode.py b/MAT/bencode/bencode.py new file mode 100644 index 0000000..739ffe5 --- /dev/null +++ b/MAT/bencode/bencode.py | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | # Copyright 2007 by Petru Paler | ||
| 2 | # Copyright 2011 by Julien (jvoisin) Voisin | ||
| 3 | # | ||
| 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 5 | # of this software and associated documentation files (the "Software"), to deal | ||
| 6 | # in the Software without restriction, including without limitation the rights | ||
| 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 8 | # copies of the Software, and to permit persons to whom the Software is | ||
| 9 | # furnished to do so, subject to the following conditions: | ||
| 10 | # | ||
| 11 | # The above copyright notice and this permission notice shall be included in | ||
| 12 | # all copies or substantial portions of the Software. | ||
| 13 | # | ||
| 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 19 | # FROM, | ||
| 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 21 | # THE SOFTWARE. | ||
| 22 | # | ||
| 23 | |||
| 24 | ''' | ||
| 25 | A quick (and also nice) lib to bencode/bdecode torrent files | ||
| 26 | ''' | ||
| 27 | |||
| 28 | |||
| 29 | import types | ||
| 30 | |||
| 31 | |||
| 32 | class BTFailure(Exception): | ||
| 33 | '''Custom Exception''' | ||
| 34 | pass | ||
| 35 | |||
| 36 | |||
| 37 | class Bencached(object): | ||
| 38 | '''Custom type : cached string''' | ||
| 39 | __slots__ = ['bencoded'] | ||
| 40 | |||
| 41 | def __init__(self, string): | ||
| 42 | self.bencoded = string | ||
| 43 | |||
| 44 | |||
| 45 | def decode_int(x, f): | ||
| 46 | '''decode an int''' | ||
| 47 | f += 1 | ||
| 48 | newf = x.index('e', f) | ||
| 49 | n = int(x[f:newf]) | ||
| 50 | if x[f] == '-': | ||
| 51 | if x[f + 1] == '0': | ||
| 52 | raise ValueError | ||
| 53 | elif x[f] == '0' and newf != f + 1: | ||
| 54 | raise ValueError | ||
| 55 | return (n, newf + 1) | ||
| 56 | |||
| 57 | |||
| 58 | def decode_string(x, f): | ||
| 59 | '''decode a string''' | ||
| 60 | colon = x.index(':', f) | ||
| 61 | n = int(x[f:colon]) | ||
| 62 | if x[f] == '0' and colon != f + 1: | ||
| 63 | raise ValueError | ||
| 64 | colon += 1 | ||
| 65 | return (x[colon:colon + n], colon + n) | ||
| 66 | |||
| 67 | |||
| 68 | def decode_list(x, f): | ||
| 69 | '''decode a list''' | ||
| 70 | result = [] | ||
| 71 | f += 1 | ||
| 72 | while x[f] != 'e': | ||
| 73 | v, f = DECODE_FUNC[x[f]](x, f) | ||
| 74 | result.append(v) | ||
| 75 | return (result, f + 1) | ||
| 76 | |||
| 77 | |||
| 78 | def decode_dict(x, f): | ||
| 79 | '''decode a dict''' | ||
| 80 | result = {} | ||
| 81 | f += 1 | ||
| 82 | while x[f] != 'e': | ||
| 83 | k, f = decode_string(x, f) | ||
| 84 | result[k], f = DECODE_FUNC[x[f]](x, f) | ||
| 85 | return (result, f + 1) | ||
| 86 | |||
| 87 | |||
| 88 | def encode_bool(x, r): | ||
| 89 | '''bencode a boolean''' | ||
| 90 | if x: | ||
| 91 | encode_int(1, r) | ||
| 92 | else: | ||
| 93 | encode_int(0, r) | ||
| 94 | |||
| 95 | |||
| 96 | def encode_int(x, r): | ||
| 97 | '''bencode an integer/float''' | ||
| 98 | r.extend(('i', str(x), 'e')) | ||
| 99 | |||
| 100 | |||
| 101 | def encode_list(x, r): | ||
| 102 | '''bencode a list/tuple''' | ||
| 103 | r.append('l') | ||
| 104 | [ENCODE_FUNC[type(item)](item, r) for item in x] | ||
| 105 | r.append('e') | ||
| 106 | |||
| 107 | |||
| 108 | def encode_dict(x, result): | ||
| 109 | '''bencode a dict''' | ||
| 110 | result.append('d') | ||
| 111 | ilist = x.items() | ||
| 112 | ilist.sort() | ||
| 113 | for k, v in ilist: | ||
| 114 | result.extend((str(len(k)), ':', k)) | ||
| 115 | ENCODE_FUNC[type(v)](v, result) | ||
| 116 | result.append('e') | ||
| 117 | |||
| 118 | |||
| 119 | DECODE_FUNC = {} | ||
| 120 | DECODE_FUNC.update(dict([(str(x), decode_string) for x in xrange(9)])) | ||
| 121 | DECODE_FUNC['l'] = decode_list | ||
| 122 | DECODE_FUNC['d'] = decode_dict | ||
| 123 | DECODE_FUNC['i'] = decode_int | ||
| 124 | |||
| 125 | |||
| 126 | ENCODE_FUNC = {} | ||
| 127 | ENCODE_FUNC[Bencached] = lambda x, r: r.append(x.bencoded) | ||
| 128 | ENCODE_FUNC[types.IntType] = encode_int | ||
| 129 | ENCODE_FUNC[types.LongType] = encode_int | ||
| 130 | ENCODE_FUNC[types.StringType] = lambda x, r: r.extend((str(len(x)), ':', x)) | ||
| 131 | ENCODE_FUNC[types.ListType] = encode_list | ||
| 132 | ENCODE_FUNC[types.TupleType] = encode_list | ||
| 133 | ENCODE_FUNC[types.DictType] = encode_dict | ||
| 134 | ENCODE_FUNC[types.BooleanType] = encode_bool | ||
| 135 | |||
| 136 | |||
| 137 | def bencode(string): | ||
| 138 | '''bencode $string''' | ||
| 139 | table = [] | ||
| 140 | ENCODE_FUNC[type(string)](string, table) | ||
| 141 | return ''.join(table) | ||
| 142 | |||
| 143 | |||
| 144 | def bdecode(string): | ||
| 145 | '''decode $string''' | ||
| 146 | try: | ||
| 147 | result, lenght = DECODE_FUNC[string[0]](string, 0) | ||
| 148 | except (IndexError, KeyError, ValueError): | ||
| 149 | raise BTFailure('Not a valid bencoded string') | ||
| 150 | if lenght != len(string): | ||
| 151 | raise BTFailure('Invalid bencoded value (data after valid prefix)') | ||
| 152 | return result | ||
