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); } } }