Vorgehensweise für Dateikonverter

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
Benutzeravatar
Ande
User
Beiträge: 24
Registriert: Donnerstag 24. März 2011, 18:36

Hallo zusammen,

ich würde mich gerne mal an einem 3d Konverter versuchen, der eine .msh Datei einliest und dann in einem anderen Format speichert.
MSH Datei Infografik:
http://ande.pytalhost.eu/msh_format.htm

Wie würde ich für so etwas am besten vorgehen? Also wie bekomme ich die Info aus dem Binary-zeugs raus? Ich hab über Google nichts gefunden... Ich will nicht unbedingt script-snippets oder so von euch, sondern eher Tipps/Links zu Tutorials/Erklärungen, wie ich mit so einem Format umgehe. Das größte Problem ist, wie ich anfangen soll. Wenn ich mal mit binary Dateien umgehen kann, dürfte der größte Schritt schon getan sein.

Danke schonmal im Vorraus für die (hoffentlich kommende) Hilfe und falls ihr noch irgendwelche Informationen braucht sagt es!
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also Du solltest Dir auf jeden Fall mal das `struct`-Modul mal angucken. Damit kannst Du binäre Werte recht gut extrahieren.

Ich kann mich daran erinnern, dass wir in einem Thread mal über div. Module gesprochen haben, die man zum Parsen von binären Formaten nutzen kann. Ich kann mich aber nicht an den Kontext erinnern; da wird es schwer, den Thread wiederzufinden :-(

Aber ich hoffe BlackJack kann sich daran noch erinnern oder weiß die Libs noch aus dem Kopf! :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

Neben `struct` könnte man noch das `ctypes`-Modul ins Auge fassen. Und wenn es auch ausserhalb der Standardbibliothek sein darf, dann sollte man sich http://construct.wikispaces.com/ mal anschauen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben:Und wenn es auch ausserhalb der Standardbibliothek sein darf, dann sollte man sich http://construct.wikispaces.com/ mal anschauen.
Das meinte ich :)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Ande
User
Beiträge: 24
Registriert: Donnerstag 24. März 2011, 18:36

Danke, hab mir mal struct und construct angeschaut. Was mir bei construct fehlt(vll find ichs auch einfach nicht)ist eine Liste mit allen Strukturen...
Für mein Dateiformat würde ich also zuerst so wie in dem PNG Beispiel Strukturen für alle Chunks definieren und dann parsen. Kann ich für chunks, die öfter vorkommen, eine eigene Struktur definieren und diese dann immer wieder aufrufen? Kann man auch bestimmte Stellen/bytes in der Datei auch einfach ignorieren?
BlackJack

@Ande: Was meinst Du jetzt mit Liste aller Strukturen? Auch die Frage nach den Chunks die öfter vorkommen verstehe ich nicht? Einige der Chunk-Typen in PNGs können mehr als einmal vorkommen. Bei jedem nicht wirklich kleinem Bild kommen zum Beispiel eigentlich immer mehr als ein IDAT-Chunk in den Daten vor. In dem PNG-Beispiel kannst Du Dir die Definition von `chunk` anschauen und wie das dann in `png_file` verwendet wird. Der Parser ist an der Stelle etwas laxer als die PNG-Spezifikation, denn nicht alle Chunk-Typen dürfen in jedem PNG vorkommen, einige dürfen nur einmal vorkommen, und es gibt auch gewisse Einschränkungen bei der Reihenfolge, die der Parser nicht prüft. Das müsste man nach dem Parsen dann auf einer höheren Ebene prüfen. Macht aber IMHO auch Sinn, weil es in einer höheren Ebene einfacher zu prüfen ist, und der Parser nicht unnötig komplex wird.

Wenn Du die Daten, die ignoriert werden sollen irgendwie mit `construct` definieren kannst, dann kannst Du sie natürlich auch ignorieren. Wenn das Format so ähnlich wie PNG entworfen wurde, dann sollte es sogar einfach sein. Da kann ja auch jeder irgendwelche eigenen Chunk-Typen erfinden und in PNGs abspeichern. Das PNG-Beispiel definiert dafür `default_chunk_info`. Die Länge von unbekannten Typen lässt sich ja ermitteln und damit kann man die auch einfach überspringen, beziehungsweise als generischen Daten-Block parsen.
BlackJack

@Ande: Ich hatte mich zu dem Format noch mal kurz im Netz umgeschaut und die Chunks scheinen ja alle als Header mit 4 Byte für den Typ und 4 Byte für die Länge des Chunks zu beginnen. Damit ist es schon mal ein leichtes komplette Chunks zu ignorieren für die man den Inhalt nicht kennt, oder an denen man nicht interessiert ist. Damit würde ich beim konstruieren eines Parsers mit `construct` auch beginnen. Einfach einer der einen oder mehr generische Chunks erkennt. Wenn der funktioniert, kann man ihn ja nach und nach mit Subparsern bestücken, die den Inhalt kennen und auswerten können.
Benutzeravatar
Ande
User
Beiträge: 24
Registriert: Donnerstag 24. März 2011, 18:36

Soweit ich weiß gibt es nur eine Seite mit Info über "mein" .msh Format und das ist die Seite woher ich die Tabelle habe, die ich im ersten Post verlinkt habe(3d model format von Pandemic Studios für die ZeroEngine[z.B. Star Wars Battlefront I+II]). Wenn es noch andere Seiten/Info gibt, dann bitte posten. ;) Und falls du mit "im Netz umgeschaut" den Link vom ersten Post meinst, oke. Die Chunks sind in diesem .msh Format ja auch jeweils 4 Bytes.
Eigentlich meinte ich mit Information, die ich ignorieren wollte einfach "leere" Bytes...
z.B.:
In einem MSH File gibts das Chunk TX0D. Das hat immer den Namen einer Textur als String hinter sich. Vor dem String kommen aber noch 4 Bytes mit den Hex-Werten:
18 00 00 00, und danach noch 2 Bytes mit 00 00. Soweit ich weiß sind Strings ja Zero terminated, also ein byte mit 00 danach(richtig?). Nach der Tabelle haben diese Bytes keinen "Sinn". Soll ich dann in construct das nur als String angeben oder davor noch die 4 Bytes mit irgendwas "ausfüllen"?

Ich bedanke mich schonmal für die ausführlichen Posts bis jetzt!
BlackJack

@Ande: Mittlerweile habe ich das Browserfenster nicht mehr offen, aber ich hatte eine Seite/Forum wo stand, dass die Chunks aus 4 Byte Namen und 4 Byte Längeninformation bestehen. Wie lang ist denn der Datenteil hinter dem TX0D? Da kommt nicht zufällig nach 16 Bytes der nächste Chunk?

Edit: Hier wird das aus der Beschreibung recht klar, dass nach dem MODL die Länge steht: http://www.gametoast.com/forums/viewtop ... 27&t=11141 Und die Chunks sind wohl alle so aufgebaut. Was auch der Bezeichnung „Chunk“ gerecht wird, denn in IFF-Dateien vom Amiga oder RIFF-Dateien unter Windows (WAV zum Beispiel) ist das auch so aufgebaut. Genau wie bei den Chunks von PNG-Dateien.
Benutzeravatar
Ande
User
Beiträge: 24
Registriert: Donnerstag 24. März 2011, 18:36

Ande hat geschrieben:Das ist jetzt schon fast peinlich... Das Forum besuche ich jeden Tag 2-3 mal, aber diesen Post habe ich nicht gefunden(oder vll ignoriert weil ich als Laie da keine relevante Info sehen konnte...).
Danke auf jeden Fall. Ich spiel die Tage mal nen bisschen mit construct und ner .msh Datei rum. Ich melde mich wieder falls ich Probleme/Fragen habe. Die schnellen Antworten hier find ich super! ;)
Da fällt mir schon die nächste ein:
Da steht ja es ist ein 4-byte long int. Wenn ich aber alle 4 bytes für den Int nutze kommt ne riesige Zahl raus. Wenn ich aber nur das erste byte nehme(wie es auch in dem Tutorial steht), kommt die Anzahl der bytes für dieses chunk raus. Ist die große Zahl also falsch oder hält die ne andere Info(zB Länge der ganzen Datei)?
Zuletzt geändert von Ande am Dienstag 25. Oktober 2011, 13:23, insgesamt 2-mal geändert.
BlackJack

@Ande: Benutzt Du die vier Bytes eventuell einfach nur falsch herum? Laut Beispiel kommt das niederwertigste Byte zuerst. Das ist auch das was unter Windows üblich wäre.

Code: Alles auswählen

In [10]: struct.unpack('<I', '\x18\x00\x00\x00')
Out[10]: (24,)

In [11]: struct.unpack('>I', '\x18\x00\x00\x00')
Out[11]: (402653184,)
Benutzeravatar
Ande
User
Beiträge: 24
Registriert: Donnerstag 24. März 2011, 18:36

Hat funktioniert, danke!
Könnte mir jemand diesen Satz erklären?
MSH Format Tabellen hat geschrieben:Values with the highest bit set (0x8000) indicate the beginning or end of a polygon.
Wie bekomm ich raus, ob das höchste Bit gesetzt/bestimmt(oder wie auch immer man das übersetzt) ist?
BlackJack

@Ande: Bitweises verknüpfen. In diesem Fall eine Und-Verknüpfung bei der nur das höchste Bit gesetzt ist. Vielleicht sollte man das hier gelesen haben: http://de.wikipedia.org/wiki/Bitweiser_Operator
Benutzeravatar
Ande
User
Beiträge: 24
Registriert: Donnerstag 24. März 2011, 18:36

Danke.
Wenn ich also rausbekommen will, ob das höchste Bit gesetzt ist mach ich das so?

Code: Alles auswählen

zahl = 72
if zahl & (1<<7) != 0:
    print 'neues polygon'
Das wäre jetzt bei 8 bits, da meine Daten aber Shorts(16-bit ints) sind müsste ich dann (1<<15) nehmen?

Ich hab grad gelesen, dass das erste bit(ist das auch das höchste?) das Vorzeichen angibt. Also kann das nicht ganz stimmen, da meine Ints normalerweise positiv sind...
Ist das höchste Bit immer das erste(linke in der Reihe)?
BlackJack

@Ande: Lass Dir das Ergebnis von ``1 << 15`` mal in Hexadezimalschreibweise ausgeben
und schau Dir den von Dir zitierten Satz in Deinem vorletzten Beitrag noch einmal an. :-)

Welches Bit ein Vorzeichen angibt oder ob überhaupt eines und wie die anderen Bits dann zu deuten sind, kommt ganz darauf an welche Bedeutung man den einzelnen Bits gibt. Deine Ints sind nur deswegen vorzeichenlos weil *Du* das halt so definierst. Beziehungsweise die Dokumentation zum Datenformat.

Mit „das höchste Bit“ meinst Du wahrscheinlich das höchst*wertige* Bit, und das ist immer das mit der höchsten Wertigkeit, egal wie herum man die Bits nun aufschreibt. Wenn man sich dabei an die übliche Weise hält, wie Dezimalzahlen notiert werden, dann ja, bei beiden steht die Ziffer mit der höchsten Wertigkeit dann links.

Nachtrag zu dem was die Bits bedeuten: Die Bitfolge 10000100 (höchswertiges Bit links) beispielweise kann man als die Zahl 132 (vorzeichenlos) interpretieren, oder auch als -4 (Einerkomplement), -124 (Zweierkomplement), oder 84 (BCD). Oder als das Zeichen 'ä' (cp850), '„' (cp1252), ein reverses 'D' (C64 Screen Code), …. Den Bits ist das herzlich egal, die haben dabei immer den gleichen Wert.
Antworten