ich bastle gerade an einem SID-Player. Da sich die Spieldauer dieser Files leider kaum berechnen lässt, gibt es eine sog. Songlength-Database, dir für jede Datei die entsprechenden Abspielzeiten bereit stellt. Es handelt sich dabei um ein INI-File mit MD5-Hashes als Schlüssel.
Um die Geschichte abzukürzen: Die MD5 Hashes werden leider nicht über die gesamte Datei berechnet sondern nur über bestimmte Teile einer Datei. Tags und andere (variable) Informationen innerhalb der Dateien werden nicht gehasht.
Um die DB nun vernünftig nutzen zu können, muss ich diesen Hash-Algo nachbauen. Die Referenz-Implementierung liegt in C vor und ich hoffe, jemand von euch hat Lust, mir dabei etwas zu helfen.
Hier meine Python-Umsetzung davon. Mir geht es eigentlich nur um die Frage, ob ich irgendwo etwas grundlegend anders mache, als es in der Datei sidtunemod.c vorgesehen ist? (Auf Code-Highlighting musste ich verzichten, weil dadurch die & in HTML umgesetzt wurden).
Code: Alles auswählen
#!/usr/bin/env python
# coding:utf-8
import hashlib
## Constants
HEADER_SIZE_V1 = 118
HEADER_SIZE_V2 = 124
LOAD_ADDRESS_SIZE = 2
CIA_SPEED = 60
VBL_SPPED = 0
NTSC_CLOCK = 2
## Bools
is_ntsc = False
is_psid_specific = False
## The file to hash and the desired result
f = "Comet.sid"
hash = "b8bc971f5eb758bcf534e27374b149b3" ## hash in the songlength db
with open(f, "rb") as fh:
content = fh.read()
md = hashlib.md5()
dataoffset = ord(content[6])<<8 | ord(content[7])
loadaddress = ord(content[8])<<8 | ord(content[9])
numsongs = ord(content[14])<<8 | ord(content[15])
IS_RSID = content[:4] == "RSID"
if not IS_RSID:
speed = ord(content[18])<<24 | ord(content[19])<<16 | ord(content[20])<<8 | ord(content[21]);
else:
speed = 4294967295
if dataoffset == HEADER_SIZE_V2:
is_ntsc = (ord(content[119])&12) == 8
if not IS_RSID:
is_psid_specific = (ord(content[119])&2) > 0
elif dataoffset != HEADER_SIZE_V1:
raise Exception("Wrong Header Size")
# loadAddress = 0 -> loadAddress is in front of the data
# loadAddress > 0 -> loadAddress is in header
if loadaddress == 0:
dataoffset += LOAD_ADDRESS_SIZE
# hash sid data (without load address)
md.update(content[dataoffset:])
md.update(content[11])
md.update(content[10])
md.update(content[13])
md.update(content[12])
md.update(content[15])
md.update(content[14])
for i in range(0, numsongs):
if not is_psid_specific:
if i < 31:
VbiSpeed = not(speed & (1<<i))
else:
VbiSpeed = not(speed & (1<<31))
else:
VbiSpeed = not(speed & (1<<(i%32)))
if VbiSpeed:
md.update(str(VBL_SPPED))
else:
md.update(str(CIA_SPEED))
if is_ntsc:
md.update(str(NTSC_CLOCK))
print "Infos:"
print "PSID: ", not IS_RSID
print "NTSC: ", is_ntsc
print "Speed: ", speed
print "Songs: ", numsongs
print md.hexdigest()
## Compare my hash with the hash from the songlengthdb
# my hash always differs :/
print md.hexdigest() == hash
MD5.c
MD5.h
sidmd5.c
sidtunemod.c
sidtunemod.h
Die SID-Datei, die ich nutze, könnt ihr hier von meinem Server laden, wenn ihr das Skript selbst mal durchlaufen lassen wollt.
Vielen Dank schonmal für eure Mühe, ich habe schon versucht, das Ganze irgendwie mit ctypes für mich nutzbar zu machen - die Portierung scheint mir aber (eigentlich) die bessere Lösung zu sein.
brb