我试图阅读/编辑暗黑破坏神的保存文件。规范here,如果有人感兴趣,但我认为这与问题无关。
我有一个带有文件字节的字节数组,我试图解析一些结构。我已经可以很好地读取文件头了,但是我遇到了任务数据问题。我得到了结构:
[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;
}
D2SFile类:
[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;
}
我使用的函数来执行字节到结构转换:
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;
}
正如我所说,我已经可以单独读取文件头而没有问题,但是当我将任务数据添加到D2SFile结构时,我得到: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.
答案 0 :(得分:5)
由于没有人回答,我已经发现了什么问题,我想我应该自己回答一下,以便任何碰巧在谷歌搜索后结束的人都会有更轻松的时间。
事实证明,你不能从不是4的倍数的偏移处开始一个数组。
在上面的示例中,QuestCompletationDataHeader
长度为10个字节,因此在QuestCompletationData
结构上,下一个字段将从位置10开始。下一个字段恰好是QuestData
struct基本上是一个大数组(现在)。所以它会尝试将该数组放在偏移量10,10处不是4的倍数,因此它给出了异常。
我更改了QuestData
结构,因此它在第一个位置没有使用数组,现在工作正常。
此外,当编组结构如上所述时,请使用[MarshalAs(UnmanagedType.Struct)]
。我正在使用[MarshalAs(UnmanagedType.LPStruct)]
,后来又给了我另一个例外。