Benötige Unterstützung bei Portierung von C nach Python

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Hallo zusammen,

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
Hier die Source-Dateien der Referenzimplementierung. Keine Sorge: So wie ich das sehe kommt es eigentlich nur auf die Datei sidtunemod.c an.
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
BlackJack

@Barabbas: Ich hab's mir nicht näher angeschaut, aber ich bin mir fast sicher dass Du an einigen Stellen `str()` verwendet hast, wo Du eigentlich `chr()` nehmen solltest. Zum Beispiel bei ``md.update(str(CIA_SPEED))``. Da denke ich mal Du willst einen Bytewert 60 und nicht zwei Bytes mit den Bytewerten für die Ziffern '6' und '0', oder!?
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

BlackJack: Vielen herzlichen Dank! Genau das war der Fehler, endlich *freu*. Ich habe das Ding soooOOoo oft auf Fehler untersucht - und das immer übersehen.

Nochmal: DANKE
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Da ich gerade Zeit hatte, habe ich die C-Implementierung ebenfalls mal umgeschrieben. Auch, wenn das Problem bereits gelöst wurde (ich war wohl zu langsam):

http://python-forum.de/pastebin.php?mod ... a3944295eb

Grüße ... Heiko
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Hallo Heiko,

trotzdem vielen Dank für deine Mühe. Mein Code war ja quasi nur zeilenweise aus C übertragen, so dass deine Implementierung schon deutlich ansehnlicher ist.

Schöne Grüße,

brb
Antworten