Hex-Editor ähnliche Formatierung von binärdaten...

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 18. November 2014, 16:21

Vielleicht kann es ja noch einer gebrauchen:

Code: Alles auswählen

import sys


PY2 = sys.version_info[0] == 2

if PY2:
    text_type = unicode
    binary_type = str
else:
    text_type = str
    binary_type = bytes


def bin2hexline(data, add_addr=True, width=16):
    assert isinstance(data, binary_type)

    addr = 0
    lines = []
    run=True
    line_width = 4 + (width*3) + 1
    while run:
        if add_addr:
            line = ["%04i" % addr]
        else:
            line = []

        ascii = ""
        for i in range(width):
            b = data[addr]

            if PY2:
                b=ord(b)

            if 33 <= b <= 126:
                ascii += chr(b)
            else:
                ascii += "."

            line.append("%02x" % b)

            addr += 1
            if addr>=len(data):
                run=False
                break

        line = " ".join(line)
        line = line.ljust(line_width)
        line += ascii
        lines.append(line)
    return lines
Bsp.:

Code: Alles auswählen

with open("C:\Python27\python.exe", "rb") as f:
    data = f.read(400)

output = bin2hexline(data, width=16)
print("\n".join(output))
Ergibt dann das:

Code: Alles auswählen

0000 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 MZ..............
0016 b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ........@.......
0032 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0048 00 00 00 00 00 00 00 00 00 00 00 00 e8 00 00 00 ................
0064 0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68 ........!..L.!Th
0080 69 73 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f is.program.canno
0096 74 20 62 65 20 72 75 6e 20 69 6e 20 44 4f 53 20 t.be.run.in.DOS.
0112 6d 6f 64 65 2e 0d 0d 0a 24 00 00 00 00 00 00 00 mode....$.......
0128 9d 68 ba 89 d9 09 d4 da d9 09 d4 da d9 09 d4 da .h..............
0144 d0 71 41 da d8 09 d4 da d0 71 50 da db 09 d4 da .qA......qP.....
0160 d0 71 47 da de 09 d4 da d9 09 d5 da f1 09 d4 da .qG.............
0176 d0 71 57 da cf 09 d4 da d0 71 40 da d8 09 d4 da .qW......q@.....
0192 d0 71 45 da d8 09 d4 da 52 69 63 68 d9 09 d4 da .qE.....Rich....
0208 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0224 00 00 00 00 00 00 00 00 50 45 00 00 4c 01 04 00 ........PE..L...
0240 d8 ec b1 53 00 00 00 00 00 00 00 00 e0 00 03 01 ...S............
0256 0b 01 09 00 00 0a 00 00 00 5a 00 00 00 00 00 00 .........Z......
0272 14 13 00 00 00 10 00 00 00 20 00 00 00 00 00 1d ................
0288 00 10 00 00 00 02 00 00 05 00 00 00 00 00 00 00 ................
0304 05 00 00 00 00 00 00 00 00 a0 00 00 00 04 00 00 ................
0320 16 e8 00 00 03 00 00 80 80 84 1e 00 00 10 00 00 ................
0336 00 00 10 00 00 10 00 00 00 00 00 00 10 00 00 00 ................
0352 00 00 00 00 00 00 00 00 04 22 00 00 50 00 00 00 ........."..P...
0368 00 40 00 00 a0 51 00 00 00 00 00 00 00 00 00 00 .@...Q..........
0384 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................


Verbesserungsvorschläge, wie immer, willkommen!

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Sirius3
User
Beiträge: 7779
Registriert: Sonntag 21. Oktober 2012, 17:20

Mittwoch 19. November 2014, 08:49

@jens: ich persönlich finde eine Variante mit nur einer Schleife übersichtlicher:

Code: Alles auswählen

import sys
PY2 = sys.version_info[0] == 2
 
if PY2:
    iter_bytes = lambda data: (ord(b) for b in data)
else:
    iter_bytes = iter


def bin2hexline(data, add_addr=True, width=16):
    lines = []
    for addr, b in enumerate(iter_bytes(data)):
        if addr % width == 0:
            hex_data = ['%04i' % addr] if add_addr else []
            bin_data = []
            lines.append((hex_data, bin_data))
        hex_data.append("%02x" % b)
        bin_data.append("%c" % b if 32 <= b <= 126 else ".")

    return ["%-*s %s" % (add_addr*4 + width*3 + 1, ' '.join(hex_data), ''.join(bin_data))
            for hex_data, bin_data in lines]
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 19. November 2014, 08:58

iter_bytes ist ja nett! Das kann ich gut gebrauchen!

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
darktrym
User
Beiträge: 706
Registriert: Freitag 24. April 2009, 09:26

Freitag 21. November 2014, 23:43

Wäre ungemein hilfreich wenn die Breite der Adresse anhand der Datenmenge berechnet wird und nicht limitiert auf 4 Stellen ist.

Shameless Self-plug, Ende der 90iger hatte ich für jemanden einen richtigen Hexeditor mit Maussteuerung in Pascal programmiert für sein Abschlussprojekt, in bunt mit Scrolling.

EDIT: So ganz klar, warum man 127 herausfiltern will ist auch nicht klar. Der Standard sagt doch Steuerzeichen nur innerhalb der ersten 32 Zeichen von ASCII. Ich seh schon, Python interpretiert das.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Samstag 22. November 2014, 00:04

127 ist Steuerzeichen DEL...

Man könnte allerdings auch string.printable nutzten. Allerdings sehe ich gerade das da auch whitespace drin ist: https://docs.python.org/2.7/library/str ... .printable

Also könnte man eine Liste aus digits, letters, punctuation machen.

Letztlich könnte man auch schauen, welche Zeichen könnten ausgegeben werden. z.B. sys.stdout.encoding...

Aber das ist alles umständlicher als dieses dumme if 33 <= b <= 126:

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten