public bool Seek(int offset, SeekOrigin whence)
{
if (!CanSeek)
{
PhpException.Throw(PhpError.Warning, ErrResources.wrapper_op_unsupported, "Seek");
return false;
}
// This is supported by any stream.
int current = Tell();
int newpos = -1;
if (whence == SeekOrigin.Begin) newpos = offset;
else if (whence == SeekOrigin.Current) newpos = current + offset;
else if (whence == SeekOrigin.End)
{
int len = RawLength();
if (len >= 0) newpos = len + offset;
}
switch (CurrentAccess)
{
case FileAccess.ReadWrite:
// Stream not R/W accessed yet. Prepare location and offset.
return SeekInternal(offset, current, whence);
case FileAccess.Read:
// Maybe we will be able to seek inside the buffers.
if ((newpos >= readOffset) && (newpos < readOffset + ReadBufferLength))
{
int streamPosition = readOffset + ReadPosition;
if (newpos > streamPosition)
{
// Seek forward
// This asserts that ReadBufferLength > 0.
int len = readBuffers.Peek().Length;
while (newpos - readOffset >= len)
{
DropReadBuffer();
len = readBuffers.Peek().Length;
}
Debug.Assert(readBuffers.Count > 0);
// All superfluous buffers are dropped, seek in the head one.
readPosition = newpos - readOffset;
}
else if (newpos < streamPosition)
{
// The required position is still in the first buffer
//. Debug.Assert(streamPosition == readOffset + readPosition);
readPosition = newpos - readOffset;
}
}
else
{
// Drop all the read buffers and proceed to the actual seeking.
readBuffers = null;
// Notice that for a filtered stream, seeking is not a good idea
if (IsReadFiltered)
{
PhpException.Throw(PhpError.Notice,
ErrResources.stream_seek_filtered, (textReadFilter != null) ? "text" : "filtered");
}
return SeekInternal(offset, current, whence);
}
break;
case FileAccess.Write:
// The following does not currently work since other methods do not take unempty writebuffer into account
//// Maybe we can seek inside of the buffer but we allow only backward skips.
//if ((newpos >= writeOffset) && (newpos < writeOffset + writePosition))
//{
// // We are inside the current buffer, great.
// writePosition = newpos - writeOffset;
//}
//else
//{
// Flush write buffers and proceed to the default handling.
FlushWriteBuffer();
// Notice that for a filtered stream, seeking is not a good idea
if (IsWriteFiltered)
{
PhpException.Throw(PhpError.Notice,
ErrResources.stream_seek_filtered, (textWriteFilter != null) ? "text" : "filtered");
}
return SeekInternal(offset, current, whence);
}
return true;
// CHECKME: [PhpStream.Seek]
}