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