int EnsureAvailable(long offset, ref int count, bool isRecursion)
{
// simple... if we're inside the buffer, just return the offset (FAST PATH)
if (offset >= _baseOffset && offset + count < _baseOffset + _end)
{
return (int)(offset - _baseOffset);
}
// not so simple... we're outside the buffer somehow...
// let's make sure the request makes sense
if (count > _maxSize)
{
throw new InvalidOperationException("Not enough room in the buffer! Increase the maximum size and try again.");
}
// make sure we always bump the version counter when a change is made to the data in the "live" buffer
++_versionCounter;
// can we satisfy the request with a saved buffer?
if (!isRecursion)
{
for (int i = 0; i < _savedBuffers.Count; i++)
{
var tempS = _savedBuffers[i].BaseOffset - offset;
if ((tempS < 0 && _savedBuffers[i].End + tempS > 0) || (tempS > 0 && count - tempS > 0))
{
SwapBuffers(_savedBuffers[i]);
return EnsureAvailable(offset, ref count, true);
}
}
}
// look for buffers we need to drop due to age...
while (_savedBuffers.Count > 0 && _savedBuffers[0].VersionSaved + 25 < _versionCounter)
{
_savedBuffers[0].Buffer = null;
_savedBuffers.RemoveAt(0);
}
// if we have to seek back, we're doomed...
if (offset < _baseOffset && !_wrapper.Source.CanSeek)
{
throw new InvalidOperationException("Cannot seek before buffer on forward-only streams!");
}
// figure up the new buffer parameters...
int readStart;
int readEnd;
CalcBuffer(offset, count, out readStart, out readEnd);
// fill the buffer...
// if we did a reverse seek, there will be data still in end of the buffer... Make sure to fill everything between
count = FillBuffer(offset, count, readStart, readEnd);
return (int)(offset - _baseOffset);
}