Fix DecalDat to work with real AC DAT files
The DAT file reader had several bugs inherited from the old C++ reference code, which targeted an older format version. Verified and fixed against real client_portal.dat and client_cell_1.dat files: - Fix header offset: BTree root is at 0x160, not 0x148 (file size field) - Fix BTree entry size: 24 bytes (flags+id+offset+size+timestamp), not 12 - Fix sector-chain node reading: BTree nodes span multiple sectors via linked-list headers; must assemble node data across sector boundaries - Fix DatStreamImpl.Read() BSTR handling: use Buffer.BlockCopy to match C++ SysAllocStringByteLen instead of Marshal.PtrToStringAnsi - Fix DatStreamImpl.ReadBinary() pointer lifetime: inline fixed block to keep destination buffer pinned during Marshal.Copy - Document LoadFilters() dependency on parameterized COM properties in IDecalCore.Configuration that need IDispatch to call correctly Add smoke test project (13/13 tests pass against real DAT files). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c0d1135431
commit
f0b6fedc9b
5 changed files with 356 additions and 56 deletions
|
|
@ -38,8 +38,14 @@ namespace Decal.DecalDat
|
|||
var buf = new byte[Bytes];
|
||||
_file.Read(buf, 0, Bytes);
|
||||
|
||||
// Copy to unmanaged buffer starting at ref Buffer
|
||||
Marshal.Copy(buf, 0, GetBufferPtr(ref Buffer), Bytes);
|
||||
// Pin the destination buffer for the duration of the copy
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* p = &Buffer)
|
||||
{
|
||||
Marshal.Copy(buf, 0, new IntPtr(p), Bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Read(int Bytes)
|
||||
|
|
@ -49,22 +55,13 @@ namespace Decal.DecalDat
|
|||
var buf = new byte[Bytes];
|
||||
int read = _file.Read(buf, 0, Bytes);
|
||||
|
||||
// Return as binary BSTR (same as SysAllocStringByteLen in C++)
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* p = buf)
|
||||
{
|
||||
return Marshal.PtrToStringAnsi(new IntPtr(p), read);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe IntPtr GetBufferPtr(ref byte buffer)
|
||||
{
|
||||
fixed (byte* p = &buffer)
|
||||
{
|
||||
return new IntPtr(p);
|
||||
}
|
||||
// Match C++ SysAllocStringByteLen: pack raw bytes into WCHAR pairs.
|
||||
// When the CLR marshals this string to BSTR, the raw bytes are preserved
|
||||
// byte-for-byte (each char = 2 raw bytes, little-endian).
|
||||
int charCount = (read + 1) / 2;
|
||||
var chars = new char[charCount];
|
||||
Buffer.BlockCopy(buf, 0, chars, 0, read);
|
||||
return new string(chars, 0, charCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue