SafeDispatch/SafeMobileLIB_DLL/FifoStream.cs

168 lines
3.5 KiB
C#

using System;
using System.IO;
using System.Collections;
namespace SafeMobileLib
{
public class FifoStream : Stream
{
private const int BlockSize = 65536;
private const int MaxBlocksInCache = (3 * 1024 * 1024) / BlockSize;
private int m_Size;
private int m_RPos;
private int m_WPos;
private Stack m_UsedBlocks = new Stack();
private ArrayList m_Blocks = new ArrayList();
private byte[] AllocBlock()
{
byte[] Result = null;
Result = m_UsedBlocks.Count > 0 ? (byte[])m_UsedBlocks.Pop() : new byte[BlockSize];
return Result;
}
private void FreeBlock(byte[] block)
{
if (m_UsedBlocks.Count < MaxBlocksInCache)
m_UsedBlocks.Push(block);
}
private byte[] GetWBlock()
{
byte[] Result = null;
if (m_WPos < BlockSize && m_Blocks.Count > 0)
Result = (byte[])m_Blocks[m_Blocks.Count - 1];
else
{
Result = AllocBlock();
m_Blocks.Add(Result);
m_WPos = 0;
}
return Result;
}
// Stream members
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return true; }
}
public override long Length
{
get
{
lock(this)
return m_Size;
}
}
public override long Position
{
get { throw new InvalidOperationException(); }
set { throw new InvalidOperationException(); }
}
public override void Close()
{
Flush();
}
public override void Flush()
{
lock(this)
{
foreach (byte[] block in m_Blocks)
FreeBlock(block);
m_Blocks.Clear();
m_RPos = 0;
m_WPos = 0;
m_Size = 0;
}
}
public override void SetLength(long len)
{
throw new InvalidOperationException();
}
public override long Seek(long pos, SeekOrigin o)
{
throw new InvalidOperationException();
}
public override int Read(byte[] buf, int ofs, int count)
{
lock(this)
{
int Result = Peek(buf, ofs, count);
Advance(Result);
return Result;
}
}
public override void Write(byte[] buf, int ofs, int count)
{
lock(this)
{
int Left = count;
while (Left > 0)
{
int ToWrite = Math.Min(BlockSize - m_WPos, Left);
Array.Copy(buf, ofs + count - Left, GetWBlock(), m_WPos, ToWrite);
m_WPos += ToWrite;
Left -= ToWrite;
}
m_Size += count;
}
}
// extra stuff
public int Advance(int count)
{
lock(this)
{
int SizeLeft = count;
while (SizeLeft > 0 && m_Size > 0)
{
if (m_RPos == BlockSize)
{
m_RPos = 0;
FreeBlock((byte[])m_Blocks[0]);
m_Blocks.RemoveAt(0);
}
int ToFeed = m_Blocks.Count == 1 ? Math.Min(m_WPos - m_RPos, SizeLeft) : Math.Min(BlockSize - m_RPos, SizeLeft);
m_RPos += ToFeed;
SizeLeft -= ToFeed;
m_Size -= ToFeed;
}
return count - SizeLeft;
}
}
public int Peek(byte[] buf, int ofs, int count)
{
lock(this)
{
int SizeLeft = count;
int TempBlockPos = m_RPos;
int TempSize = m_Size;
int CurrentBlock = 0;
while (SizeLeft > 0 && TempSize > 0)
{
if (TempBlockPos == BlockSize)
{
TempBlockPos = 0;
CurrentBlock++;
}
int Upper = CurrentBlock < m_Blocks.Count - 1 ? BlockSize : m_WPos;
int ToFeed = Math.Min(Upper - TempBlockPos, SizeLeft);
Array.Copy((byte[])m_Blocks[CurrentBlock], TempBlockPos, buf, ofs + count - SizeLeft, ToFeed);
SizeLeft -= ToFeed;
TempBlockPos += ToFeed;
TempSize -= ToFeed;
}
return count - SizeLeft;
}
}
}
}