using System; using System.Runtime.InteropServices; using Decal.Interop.Dat; namespace Decal.DecalDat { [ComVisible(true)] [Guid("9F7F6CD9-D164-418D-8CB5-3B9ACD70BEAF")] [ClassInterface(ClassInterfaceType.None)] [ProgId("DecalDat.DatStream")] public class DatStreamImpl : IDatStream { private DatFileEntry _file; internal void Load(DatFileEntry file) { _file = file; } public int Size => _file?.Size ?? 0; public int Tell => _file?.Tell ?? 0; public void Skip(int Bytes) { _file?.Skip(Bytes); } public void Restart() { _file?.Reset(); } public void ReadBinary(int Bytes, ref byte Buffer) { if (_file == null) return; var buf = new byte[Bytes]; _file.Read(buf, 0, 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) { if (_file == null) return string.Empty; var buf = new byte[Bytes]; int read = _file.Read(buf, 0, Bytes); // 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); } } }