109 lines
3 KiB
Python
Executable file
109 lines
3 KiB
Python
Executable file
#! /usr/bin/python3
|
||
|
||
import collections
|
||
|
||
def bencode(elem):
|
||
if type(elem) == str:
|
||
elem = str.encode(elem)
|
||
|
||
if type(elem) == bytes:
|
||
result = str.encode(str(len(elem)))+b":"+elem
|
||
elif type(elem) == int:
|
||
result = str.encode("i"+str(elem)+"e")
|
||
elif type(elem) == list:
|
||
result = b"l"
|
||
for item in elem:
|
||
result += bencode(item)
|
||
result += b"e"
|
||
elif type(elem) in [dict, collections.OrderedDict]:
|
||
result = b"d"
|
||
for key in elem:
|
||
result += bencode(key)+bencode(elem[key])
|
||
result += b"e"
|
||
return result
|
||
|
||
def bdecode(bytestr, recursiveCall=False):
|
||
startingChars = dict({
|
||
b"i" : int,
|
||
b":" : str,
|
||
b"l" : list,
|
||
b"d" : dict
|
||
})
|
||
digits = [b"0", b"1", b"2", b"3", b"4", b"5", b"6", b"7", b"8", b"9"]
|
||
|
||
started = ended = False
|
||
curtype = None
|
||
|
||
numstring = b"" # for str, int
|
||
result = None # for list, dict
|
||
key = None # for dict
|
||
|
||
while len(bytestr) > 0:
|
||
# reading and popping from the beginning
|
||
char = bytestr[:1]
|
||
|
||
if not started:
|
||
|
||
bytestr = bytestr[1:]
|
||
|
||
if char in digits:
|
||
numstring += char
|
||
|
||
elif char in startingChars:
|
||
|
||
started = True
|
||
curtype = startingChars[char]
|
||
|
||
if curtype == str:
|
||
size = int(bytes.decode(numstring))
|
||
# try to decode strings
|
||
try:
|
||
result = bytes.decode(bytestr[:size])
|
||
except UnicodeDecodeError:
|
||
result = bytestr[:size]
|
||
bytestr = bytestr[size:]
|
||
ended = True
|
||
break
|
||
|
||
elif curtype == list:
|
||
result = []
|
||
|
||
elif curtype == dict:
|
||
result = collections.OrderedDict()
|
||
else:
|
||
raise ValueError("Expected starting char, got ‘"+bytes.decode(char)+"’")
|
||
|
||
else: # if started
|
||
|
||
if not char == b"e":
|
||
|
||
if curtype == int:
|
||
bytestr = bytestr[1:]
|
||
numstring += char
|
||
|
||
elif curtype == list:
|
||
item, bytestr = bdecode(bytestr, recursiveCall=True)
|
||
result.append(item)
|
||
|
||
elif curtype == dict:
|
||
|
||
if key == None:
|
||
key, bytestr = bdecode(bytestr, recursiveCall=True)
|
||
|
||
else:
|
||
result[key], bytestr = bdecode(bytestr, recursiveCall=True)
|
||
key = None
|
||
|
||
else: # ending: char == b"e"
|
||
bytestr = bytestr[1:]
|
||
if curtype == int:
|
||
result = int(bytes.decode(numstring))
|
||
ended = True
|
||
break
|
||
if ended:
|
||
if recursiveCall:
|
||
return result, bytestr
|
||
else:
|
||
return result
|
||
else:
|
||
raise ValueError("String ended unexpectedly")
|