173 lines
3.7 KiB
C#
173 lines
3.7 KiB
C#
using System;
|
|
using System.Threading;
|
|
|
|
namespace SharpCifs.Util.Sharpen
|
|
{
|
|
internal class PipedInputStream : InputStream
|
|
{
|
|
private byte[] _oneBuffer;
|
|
public const int PipeSize = 1024;
|
|
|
|
protected byte[] Buffer;
|
|
private bool _closed;
|
|
private ManualResetEvent _dataEvent;
|
|
private int _end;
|
|
private int _start;
|
|
private object _thisLock;
|
|
private bool _allowGrow = false;
|
|
|
|
public int In {
|
|
get { return _start; }
|
|
set { _start = value; }
|
|
}
|
|
|
|
public int Out {
|
|
get { return _end; }
|
|
set { _end = value; }
|
|
}
|
|
|
|
public PipedInputStream ()
|
|
{
|
|
_thisLock = new object ();
|
|
_dataEvent = new ManualResetEvent (false);
|
|
Buffer = new byte[PipeSize + 1];
|
|
}
|
|
|
|
public PipedInputStream (PipedOutputStream os): this ()
|
|
{
|
|
os.Attach (this);
|
|
}
|
|
|
|
public override void Close ()
|
|
{
|
|
lock (_thisLock) {
|
|
_closed = true;
|
|
_dataEvent.Set ();
|
|
}
|
|
}
|
|
|
|
public override int Available ()
|
|
{
|
|
lock (_thisLock) {
|
|
if (_start <= _end) {
|
|
return (_end - _start);
|
|
}
|
|
return ((Buffer.Length - _start) + _end);
|
|
}
|
|
}
|
|
|
|
public override int Read ()
|
|
{
|
|
if (_oneBuffer == null)
|
|
_oneBuffer = new byte[1];
|
|
if (Read (_oneBuffer, 0, 1) == -1)
|
|
return -1;
|
|
return _oneBuffer[0];
|
|
}
|
|
|
|
public override int Read (byte[] b, int offset, int len)
|
|
{
|
|
int length = 0;
|
|
do {
|
|
_dataEvent.WaitOne ();
|
|
lock (_thisLock) {
|
|
if (_closed && Available () == 0) {
|
|
return -1;
|
|
}
|
|
if (_start < _end) {
|
|
length = Math.Min (len, _end - _start);
|
|
Array.Copy (Buffer, _start, b, offset, length);
|
|
_start += length;
|
|
} else if (_start > _end) {
|
|
length = Math.Min (len, Buffer.Length - _start);
|
|
Array.Copy (Buffer, _start, b, offset, length);
|
|
len -= length;
|
|
_start = (_start + length) % Buffer.Length;
|
|
if (len > 0) {
|
|
int i = Math.Min (len, _end);
|
|
Array.Copy (Buffer, 0, b, offset + length, i);
|
|
_start += i;
|
|
length += i;
|
|
}
|
|
}
|
|
if (_start == _end && !_closed) {
|
|
_dataEvent.Reset ();
|
|
}
|
|
Monitor.PulseAll (_thisLock);
|
|
}
|
|
} while (length == 0);
|
|
return length;
|
|
}
|
|
|
|
private int Allocate (int len)
|
|
{
|
|
int alen;
|
|
while ((alen = TryAllocate (len)) == 0) {
|
|
// Wait until somebody reads data
|
|
try {
|
|
Monitor.Wait (_thisLock);
|
|
} catch {
|
|
_closed = true;
|
|
_dataEvent.Set ();
|
|
throw;
|
|
}
|
|
}
|
|
return alen;
|
|
}
|
|
|
|
int TryAllocate (int len)
|
|
{
|
|
int free;
|
|
if (_start <= _end) {
|
|
free = (Buffer.Length - _end) + _start;
|
|
} else {
|
|
free = _start - _end;
|
|
}
|
|
if (free <= len) {
|
|
if (!_allowGrow)
|
|
return free > 0 ? free - 1 : 0;
|
|
int sizeInc = (len - free) + 1;
|
|
byte[] destinationArray = new byte[Buffer.Length + sizeInc];
|
|
if (_start <= _end) {
|
|
Array.Copy (Buffer, _start, destinationArray, _start, _end - _start);
|
|
} else {
|
|
Array.Copy (Buffer, 0, destinationArray, 0, _end);
|
|
Array.Copy (Buffer, _start, destinationArray, _start + sizeInc, Buffer.Length - _start);
|
|
_start += sizeInc;
|
|
}
|
|
Buffer = destinationArray;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
internal void Write (int b)
|
|
{
|
|
lock (_thisLock) {
|
|
Allocate (1);
|
|
Buffer[_end] = (byte)b;
|
|
_end = (_end + 1) % Buffer.Length;
|
|
_dataEvent.Set ();
|
|
}
|
|
}
|
|
|
|
internal void Write (byte[] b, int offset, int len)
|
|
{
|
|
do {
|
|
lock (_thisLock) {
|
|
int alen = Allocate (len);
|
|
int length = Math.Min (Buffer.Length - _end, alen);
|
|
Array.Copy (b, offset, Buffer, _end, length);
|
|
_end = (_end + length) % Buffer.Length;
|
|
if (length < alen) {
|
|
Array.Copy (b, offset + length, Buffer, 0, alen - length);
|
|
_end += alen - length;
|
|
}
|
|
_dataEvent.Set ();
|
|
len -= alen;
|
|
offset += alen;
|
|
}
|
|
} while (len > 0);
|
|
}
|
|
}
|
|
}
|