A codificación permite representar catro tipos de datos, números enteiros, cadeas de caracteres (non necesariamente lexibles), listas e diccionarios.
Para saber o tipo de dato que é temos que ler o primer carácter, se é un 'i', e enteiro; 'l', lista; 'd', diccionario; e un número, cadea de caracteres.
def decode_torrent(f):
c = f.read(1)
if c == 'i': return decode_int(f)
elif c == 'l': return decode_list(f)
elif c == 'd': return decode_dict(f)
elif c == 'e': return None # Xa veremos para que funciona :)
elif c in map(str, range(10)): return decode_string(c, f)
else: raise Exception('Invalid character ', c)
No caso de ser un enteiro o que atopamos é o número escrito en texto, acabado cunha 'e', por exemplo:
i1234eEntón, a rutina para decodificalo é simple:
def decode_int(f):
nums = []
c = f.read(1)
while c != 'e':
nums.append(c)
c = f.read(1)
# Xuntamos tódo-los caracteres e convertímolos nun número
return int(''.join(nums))
No caso dunha lista igual, lemos todos os elementos ata atopar unha 'e', se tiramos uso da función 'decode_torrent' queda ate máis sinxelo:
def decode_list(f):
l = []
item = decode_torrent(f)
while item != None:
l.append(item)
item = decode_torrent(f)
return l
Se o tema a tratar son os diccionarios á complicación tampouco é excesiva, só temos que ler os elementos por pares, o primeiro será o índice e o segundo o valor, se o índice é unha 'e' pois xa non seguimos:
def decode_dict(f):
d = {}
key = decode_torrent(f)
while key != None:
value = decode_torrent(f)
d[key] = value
key = decode_torrent(f)
return d
Por último, ó ler as cadeas atopamonos primeiro coa súa lonxutide, de novo expresada coma un número en texto e acabado cun ':', so temos que tomar ese número (chamemoslle 'lonx') e ler os seguintes 'lonx' caracteres:
def decode_string(n, f):
# Lemos o tamanho
l = [n]
c = f.read(1)
while c != ':':
l.append(c)
c = f.read(1)
# Feito iso só queda ler
lonxitude = int(''.join(l))
return f.read(lonxitude)
E xa está, un arquivo .torrent decodificado en menos de 50 liñas de código (formateado a man ;) ):
>>> decode_torrent(open('trisquel_5.5_i686.iso.torrent'))
{'comment': 'Trisquel GNU/Linux 5.5 brigantia. i686 Installable Live CD',
'info': {'length': 729808896,
'piece length': 262144,
'name': 'trisquel_5.5_i686.iso',
'pieces': '(eliminado por brevedade, son os hashes das pezas do arquivo)'},
'creation date': 1334183204,
'created by': 'mktorrent 1.0',
'announce': 'http://trisquel.info:6969/announce',
'url-list': ['http://cdimage.trisquel.info/trisquel-images/trisquel_5.5_i686.iso',
'http://gdsol.uta.cl/trisquel/iso/trisquel_5.5_i686.iso',
'http://us.archive.trisquel.info/iso/trisquel_5.5_i686.iso',
'http://es.gnu.org/~ruben/trisquel/trisquel_5.5_i686.iso',
'http://ftp.linux.org.tr/trisquel/iso/trisquel_5.5_i686.iso',
'http://ftp.rediris.es/mirror/Trisquel/iso/trisquel_5.5_i686.iso',
'http://nl.cdimage.trisquel.info/trisquel_5.5_i686.iso',
'ftp://in.archive.trisquel.info/trisquel-iso/trisquel_5.5_i686.iso',
'http://ibelin.mx.gnu.org/trisquel_5.5_i686.iso',
'http://ftp.linux.org.tr/trisquel/iso/trisquel_5.5_i686.iso']}
>>>
No hay comentarios:
Publicar un comentario