Beispiel #1
0
        public override IAsyncResult BeginWrite(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)
        {
            if (array == null)
            {
                throw new ArgumentNullException("array");
            }
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset", Helper.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
            }
            if (numBytes < 0)
            {
                throw new ArgumentOutOfRangeException("numBytes", Helper.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
            }
            if (array.Length - offset < numBytes)
            {
                throw new ArgumentException(Helper.GetResourceString("Argument_InvalidOffLen"));
            }

            if (!CanWrite)
            {
                __Error.WriteNotSupported();
            }

            Debug.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");

            if (_writePos == 0)
            {
                if (_readPos < _readLen)
                {
                    FlushRead();
                }
                _readPos = 0;
                _readLen = 0;
            }

            int n = bufferSize - _writePos;

            if (numBytes <= n)
            {
                if (_buffer == null)
                {
                    _buffer = new byte[bufferSize];
                }
                Buffer.BlockCopy(array, offset, _buffer, _writePos, numBytes);
                _writePos += numBytes;

                return(BufferedStreamAsyncResult.Complete(numBytes, userCallback, stateObject, true));
            }

            if (_writePos > 0)
            {
                FlushWrite(false);
            }
            return(BeginWriteCore(array, offset, numBytes, userCallback, stateObject));
        }
Beispiel #2
0
        public override long Seek(long offset, SeekOrigin origin)
        {
            if (origin < SeekOrigin.Begin || origin > SeekOrigin.End)
            {
                throw new ArgumentException(Helper.GetResourceString("Argument_InvalidSeekOrigin"));
            }

            if (!CanSeek)
            {
                __Error.SeekNotSupported();
            }

            Debug.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");

            // If we've got bytes in our buffer to write, write them out.
            // If we've read in and consumed some bytes, we'll have to adjust
            // our seek positions ONLY IF we're seeking relative to the current
            // position in the stream.  This simulates doing a seek to the new
            // position, then a read for the number of bytes we have in our buffer.
            if (_writePos > 0)
            {
                FlushWrite(false);
            }
            else if (origin == SeekOrigin.Current)
            {
                // Don't call FlushRead here, which would have caused an infinite
                // loop.  Simply adjust the seek origin.  This isn't necessary
                // if we're seeking relative to the beginning or end of the stream.
                offset -= (_readLen - _readPos);
            }

            long oldPos = pos + (_readPos - _readLen);
            long curPos = SeekCore(offset, origin);

            // We now must update the read buffer.  We can in some cases simply
            // update _readPos within the buffer, copy around the buffer so our
            // Position property is still correct, and avoid having to do more
            // reads from the disk.  Otherwise, discard the buffer's contents.
            if (_readLen > 0)
            {
                // We can optimize the following condition:
                // oldPos - _readPos <= curPos < oldPos + _readLen - _readPos
                if (oldPos == curPos)
                {
                    if (_readPos > 0)
                    {
                        Buffer.BlockCopy(_buffer, _readPos, _buffer, 0, _readLen - _readPos);
                        _readLen -= _readPos;
                        _readPos  = 0;
                    }
                    // If we still have buffered data, we must update the stream's
                    // position so our Position property is correct.
                    if (_readLen > 0)
                    {
                        SeekCore(_readLen, SeekOrigin.Current);
                    }
                }
                else if (oldPos - _readPos < curPos && curPos < oldPos + _readLen - _readPos)
                {
                    int diff = (int)(curPos - oldPos);
                    Buffer.BlockCopy(_buffer, _readPos + diff, _buffer, 0, _readLen - (_readPos + diff));
                    _readLen -= (_readPos + diff);
                    _readPos  = 0;
                    if (_readLen > 0)
                    {
                        SeekCore(_readLen, SeekOrigin.Current);
                    }
                }
                else
                {
                    // Lose the read buffer.
                    _readPos = 0;
                    _readLen = 0;
                }
                Debug.Assert(_readLen >= 0 && _readPos <= _readLen, "_readLen should be nonnegative, and _readPos should be less than or equal _readLen");
                Debug.Assert(curPos == Position, "Seek optimization: curPos != Position!  Buffer math was mangled.");
            }
            return(curPos);
        }
Beispiel #3
0
        public override IAsyncResult BeginRead(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)
        {
            if (array == null)
            {
                throw new ArgumentNullException("array");
            }
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset", Helper.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
            }
            if (numBytes < 0)
            {
                throw new ArgumentOutOfRangeException("numBytes", Helper.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
            }
            if (array.Length - offset < numBytes)
            {
                throw new ArgumentException(Helper.GetResourceString("Argument_InvalidOffLen"));
            }

            if (!CanRead)
            {
                __Error.ReadNotSupported();
            }

            Debug.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");

            if (_writePos > 0)
            {
                FlushWrite(false);
            }
            if (_readPos == _readLen)
            {
                // I can't see how to handle buffering of async requests when
                // filling the buffer asynchronously, without a lot of complexity.
                // The problems I see are issuing an async read, we do an async
                // read to fill the buffer, then someone issues another read
                // (either synchronously or asynchronously) before the first one
                // returns.  This would involve some sort of complex buffer locking
                // that we probably don't want to get into, at least not in V1.
                // If we did a sync read to fill the buffer, we could avoid the
                // problem, and any async read less than 64K gets turned into a
                // synchronous read by NT anyways...       --

                if (numBytes < bufferSize)
                {
                    if (_buffer == null)
                    {
                        _buffer = new byte[bufferSize];
                    }
                    IAsyncResult bufferRead = BeginReadCore(_buffer, 0, bufferSize, null, null, 0);
                    _readLen = EndRead(bufferRead);
                    int n = _readLen;
                    if (n > numBytes)
                    {
                        n = numBytes;
                    }
                    Buffer.BlockCopy(_buffer, 0, array, offset, n);
                    _readPos = n;

                    // Fake async
                    return(BufferedStreamAsyncResult.Complete(n, userCallback, stateObject, false));
                }

                // Here we're making our position pointer inconsistent
                // with our read buffer.  Throw away the read buffer's contents.
                _readPos = 0;
                _readLen = 0;
                return(BeginReadCore(array, offset, numBytes, userCallback, stateObject, 0));
            }
            else
            {
                int n = _readLen - _readPos;
                if (n > numBytes)
                {
                    n = numBytes;
                }
                Buffer.BlockCopy(_buffer, _readPos, array, offset, n);
                _readPos += n;

                if (n >= numBytes)
                {
                    return(BufferedStreamAsyncResult.Complete(n, userCallback, stateObject, false));
                }

                // For streams with no clear EOF like serial ports or pipes
                // we cannot read more data without causing an app to block
                // incorrectly.  Pipes don't go down this path
                // though.  This code needs to be fixed.
                // Throw away read buffer.
                _readPos = 0;
                _readLen = 0;

                // WARNING: all state on asyncResult objects must be set before
                // we call ReadFile in BeginReadCore, since the OS can run our
                // callback & the user's callback before ReadFile returns.
                return(BeginReadCore(array, offset + n, numBytes - n, userCallback, stateObject, n));
            }
        }
Beispiel #4
0
        public override int Read(/*[In, Out]*/ byte[] array, int offset, int count)
        {
            if (array == null)
            {
                throw new ArgumentNullException("array", Helper.GetResourceString("ArgumentNull_Buffer"));
            }
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset", Helper.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
            }
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException("count", Helper.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
            }
            if (array.Length - offset < count)
            {
                throw new ArgumentException(Helper.GetResourceString("Argument_InvalidOffLen"));
            }

            Debug.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");

            bool isBlocked = false;
            int  n         = _readLen - _readPos;

            // If the read buffer is empty, read into either user's array or our
            // buffer, depending on number of bytes user asked for and buffer size.
            if (n == 0)
            {
                if (!CanRead)
                {
                    __Error.ReadNotSupported();
                }
                if (_writePos > 0)
                {
                    FlushWrite(false);
                }
                if (!CanSeek || (count >= bufferSize))
                {
                    n = ReadCore(array, offset, count);
                    // Throw away read buffer.
                    _readPos = 0;
                    _readLen = 0;
                    return(n);
                }
                if (_buffer == null)
                {
                    _buffer = new byte[bufferSize];
                }
                n = ReadCore(_buffer, 0, bufferSize);
                if (n == 0)
                {
                    return(0);
                }
                isBlocked = n < bufferSize;
                _readPos  = 0;
                _readLen  = n;
            }

            // Now copy min of count or numBytesAvailable (ie, near EOF) to array.
            if (n > count)
            {
                n = count;
            }
            Buffer.BlockCopy(_buffer, _readPos, array, offset, n);
            _readPos += n;

            // We may have read less than the number of bytes the user asked
            // for, but that is part of the Stream contract.  Reading again for
            // more data may cause us to block if we're using a device with
            // no clear end of file, such as a serial port or pipe.  If we
            // blocked here & this code was used with redirected pipes for a
            // process's standard output, this can lead to deadlocks involving
            // two processes. But leave this here for files to avoid what would
            // probably be a breaking change.         --

            return(n);
        }