using System; using System.Runtime.InteropServices; namespace DiskAccessLibrary.Mod { public class UnmanagedGigabyteBlockSeparatedRamDisk : Disk, ILoadableRamDisk { private const int SectorSize = 512; private const int BlockSize = Consts.Gigabyte; private IntPtr[] _blocks; public UnmanagedGigabyteBlockSeparatedRamDisk(int sizeInGigabyte) { _blocks = new IntPtr[sizeInGigabyte]; Size = (long)sizeInGigabyte * Consts.Gigabyte; } public void Allocate() { for (var i = 0; i < _blocks.Length; i++) { _blocks[i] = Marshal.AllocHGlobal(BlockSize); } } public void Free() { foreach (var block in _blocks) { if (block != IntPtr.Zero) Marshal.FreeHGlobal(block); } _blocks = null; GC.Collect(); GC.WaitForPendingFinalizers(); } private void ReadBlock(byte[] buffer, int offset, int count, int blockIndex, int blockOffset) { Marshal.Copy(_blocks[blockIndex] + blockOffset, buffer, offset, count); } private void WriteBlock(byte[] buffer, int offset, int count, int blockIndex, int blockOffset) { Marshal.Copy(buffer, offset, _blocks[blockIndex] + blockOffset, count); } public void WriteData(long rawOffset, byte[] data) { for (var i = 0; i < data.Length;) { var blockIndex = (int)(rawOffset / BlockSize); var blockOffset = (int)(rawOffset % BlockSize); var bytesToWrite = BlockSize - blockOffset; if (i + bytesToWrite > data.Length) { bytesToWrite = data.Length - i; } WriteBlock(data, i, bytesToWrite, blockIndex, blockOffset); i += bytesToWrite; rawOffset += bytesToWrite; } } public override byte[] ReadSectors(long sectorIndex, int sectorCount) { var rawOffset = sectorIndex * SectorSize; var rawSize = sectorCount * SectorSize; var buffer = new byte[rawSize]; for (var i = 0; i < rawSize;) { var blockIndex = (int)(rawOffset / BlockSize); var blockOffset = (int)(rawOffset % BlockSize); var bytesToRead = BlockSize - blockOffset; if (i + bytesToRead > rawSize) { bytesToRead = rawSize - i; } ReadBlock(buffer, i, bytesToRead, blockIndex, blockOffset); i += bytesToRead; rawOffset += bytesToRead; } return buffer; } public override void WriteSectors(long sectorIndex, byte[] data) { var rawOffset = sectorIndex * SectorSize; WriteData(rawOffset, data); } public override int BytesPerSector => SectorSize; public override long Size { get; } } }