[JAVA] byte[] to Object (ähnlich wie in C byte[] zu struct) möglich?

Hallo,

Ich bin gerade dabei mir ein Tool zu schreiben, welches den PE-Header (+DOS Header) einer Datei auslesen soll. Als Sprache habe ich Java gewählt (warum? weil ich es so will :P). Nun bin ich direkt zu Beginn auf eine kleine Unbequemlichkeit gestoßen, bei der ich mir nicht sicher bin, ob das ganze nicht auch einfacher funktioniert.
Wenn ich in C nun die Struktur IMAGE_DOS_HEADER habe:
Code:
typedef struct _IMAGE_DOS_HEADER
{
     WORD e_magic;
     WORD e_cblp;
     WORD e_cp;
     WORD e_crlc;
     WORD e_cparhdr;
     WORD e_minalloc;
     WORD e_maxalloc;
     WORD e_ss;
     WORD e_sp;
     WORD e_csum;
     WORD e_ip;
     WORD e_cs;
     WORD e_lfarlc;
     WORD e_ovno;
     WORD e_res[4];
     WORD e_oemid;
     WORD e_oeminfo;
     WORD e_res2[10];
     LONG e_lfanew;
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
So kann ich (insofern ich mich recht entsinne) nachdem ich die Bytes der Datei gelesen habe die Struktur einfach "füllen", indem ich nach IMAGE_DOS_HEADER caste.

Gibt es einen derartigen "Mechanismus" auch in Java? Mein bisheriger Ansatz war, dass ich die entsprechende Klasse in Java manuell fülle, was natürlich nicht schwer ist, jedoch in einem unschönen großen Code resultiert, da man sich zum Beispiel auch um Little Endian selber kümmern muss. Und da man das Rad ja nicht jedes mal aufs Neue erfinden muss wollte ich wissen, ob das ganze auch einfacher funktioniert.

Viele Grüße

PHRoZeNCReW
 
Gibt es einen derartigen "Mechanismus" auch in Java?
Nein, da Java keine Pointer kennt.

[...] Und da man das Rad ja nicht jedes mal aufs Neue erfinden muss wollte ich wissen, ob das ganze auch einfacher funktioniert.
Ja, es gibt schon fertige Klassen, die diesen Job übernehmen: https://www.cs.arizona.edu/projects/mbel/javadoc/edu/arizona/cs/mbel/parse/package-summary.html http://pecoff4j.sourceforge.net/
 
mal abgesehen von der aktuellen anwendung, und fertigen implementationen für diese... wenn man das allgemein haben will, könnte man versuchen einen spezifischen wrapper über einen java.nio.ByteBuffer zu legen...
 
Hallo,

Vielen Dank für eure Antworten.

@xrayn
Danke für den Link. Aber so viel vom Rad will ich dann doch noch selber erfinden :).

@GrafZahl
Der Bytebuffer scheint ein guter Anfang zu sein :). Ich habe nochmal etwas recherchiert und die bequemste Lösung (meiner Meinung nach) scheint wohl Bytebuffer + Reflection zu sein: Java Getriebe » Blog Archive » Binärdateien auslesen mit dem ByteBuffer

Wenn man das ganze noch ein wenig anpasst, kann man ganz problemlos die "Strukturen" füllen.

Code:
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;

public abstract class Struct {
    private Object getValue(Object obj, ByteBuffer buffer) {
        if (obj instanceof Byte) {
            return buffer.get();
        } else if (obj instanceof Short) {
            return buffer.getShort();
        } else if (obj instanceof Integer) {
            return buffer.getInt();
        } else if (obj instanceof Long) {
            return buffer.getLong();
        } else if (obj instanceof Float) {
            return buffer.getFloat();
        } else if (obj instanceof Double) {
            return buffer.getDouble();
        } else if (obj.getClass().isArray()) {
            int n = Array.getLength(obj);
            Object arr = Array
                    .newInstance(obj.getClass().getComponentType(), n);
            for (int i = 0; i < n; i++) {
                Array.set(arr, i, getValue(Array.get(obj, i), buffer));
            }
            return arr;
        } else if (obj instanceof Struct) {
            Struct struct = (Struct) obj;
            struct.read(buffer);

            return struct;
        } else {
            return null;
        }
    }

    public void read(ByteBuffer buffer) {
        Field[] fields = getClass().getFields();
        for (Field field : fields) {
            try {
                field.set(this, getValue(field.get(this), buffer));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
Code:
public class IMAGE_DOS_HEADER extends Struct {
    public short e_magic;
    public short e_cblp;
    public short e_cp;
    public short e_crlc;
    public short e_cparhdr;
    public short e_minalloc;
    public short e_maxalloc;
    public short e_ss;
    public short e_sp;
    public short e_csum;
    public short e_ip;
    public short e_cs;
    public short e_lfarlc;
    public short e_ovno;
    public short[] e_res = new short[4];
    public short e_oemid;
    public short e_oeminfo;
    public short[] e_res2 = new short[10];
    public int e_lfanew;
}

Das Einlesen ist dann recht leicht:
Code:
Path path = Paths.get("pfad\zur\datei");
byte[] test = Files.readAllBytes(path);
ByteBuffer buf = ByteBuffer.wrap(test);
buf.order(ByteOrder.LITTLE_ENDIAN);

IMAGE_DOS_HEADER dos = new IMAGE_DOS_HEADER();
dos.read(buf);
 
Zuletzt bearbeitet:
Zurück
Oben