Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting "incorrectly aligned or overlapped by non-object" error on explicit struct

I'm trying to read/edit Diablo's save file. Specification here, if anyone's interested, but I dont think it is relevant to the question.

I have a byte array with the file bytes that i'm trying to parse to some structs. I can already read the file header fine, btu im having trouble with the quests data. I got there structs:

[StructLayout(LayoutKind.Explicit, Size = 10, Pack = 1)]
public struct QuestCompletationDataHeader {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    [FieldOffset(0)]
    public string Identifier;
    [FieldOffset(4)]
    uint _0x0004;
    [FieldOffset(8)]
    short _0x008;
}

[StructLayout(LayoutKind.Explicit, Size = 96, Pack = 1)]
public struct QuestData {
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 96, ArraySubType = UnmanagedType.U1)]
    [FieldOffset(0)]
    byte[] _0x0000; //Irrelevant for now.
}

[StructLayout(LayoutKind.Explicit, Size = 298, Pack = 1)]
public struct QuestCompletationData {
    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(0)]
    QuestCompletationDataHeader Header;

    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(10)]
    QuestData NormalQuests;

    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(106)]
    QuestData NightmareQuests;

    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(202)]
    QuestData HellQuests;

}

The D2SFile class:

[StructLayout(LayoutKind.Explicit, Size = 638, Pack = 1)]
public struct D2SFile {
    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(0)]
    public D2SHeader Header;

    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(335)]
    public QuestCompletationData Quests;
}

And the function Im using to do the byte to struct conversion:

 public static D2SFile ByteArrayToD2SFile(byte[] bytes) {
        GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        D2SFile stuff = (D2SFile)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(D2SFile));
        handle.Free();
        return stuff;
    }

As I said, I can already read the file header alone without a problem, but when I add the quest data to the D2SFile struct I get: Could not load type 'MedianXLEditor.QuestCompletationData' from assembly '...' because it contains an object field at offset 10 that is incorrectly aligned or overlapped by a non-object field.

like image 736
markhc Avatar asked Jan 21 '15 03:01

markhc


1 Answers

Since no one answered and I already found out what was wrong I think I should answer it myself so that anyone that happens to end up here after googling have a easier time.

It turns out you cant have a array starting at offsets that are not multiples of 4.

On the example above, the QuestCompletationDataHeader is 10 bytes long, so on the QuestCompletationData struct the next field will start at position 10. The next field happens to be of the QuestData struct which is basically a big array (for now). So it will try to place that array at the offset 10, 10 is not a multiple of 4 so it gives the exception.

I changed the QuestData struct so it does not use a array on the first position and it works fine now.

Also, use [MarshalAs(UnmanagedType.Struct)] when Marshalling structs like the ones above. I was using [MarshalAs(UnmanagedType.LPStruct)] which gave me another exception later.

like image 136
markhc Avatar answered Oct 14 '22 15:10

markhc