internal Midpoint[] CacheMidpointsAndVerifyHash(int depth)
{
var buffer = new byte[4096];
if (depth < 0 || depth > 30)
throw new ArgumentOutOfRangeException("depth");
var count = Count;
if (count == 0 || depth == 0)
return null;
#if __MonoCS__
var workItem = GetWorkItem();
var stream = workItem.Stream;
try {
#else
using (var stream = UnbufferedFileStream.Create(_filename, FileMode.Open, FileAccess.Read, FileShare.Read, false, 4096, 4096, false, 4096))
{
#endif
try {
int midpointsCount;
Midpoint[] midpoints;
using (MD5 md5 = MD5.Create())
{
try
{
midpointsCount = (int)Math.Max(2L, Math.Min((long)1 << depth, count));
midpoints = new Midpoint[midpointsCount];
}
catch (OutOfMemoryException exc)
{
throw new PossibleToHandleOutOfMemoryException("Failed to allocate memory for Midpoint cache.", exc);
}
stream.Seek(0, SeekOrigin.Begin);
stream.Read(buffer, 0, PTableHeader.Size);
md5.TransformBlock(buffer, 0, PTableHeader.Size, null, 0);
long previousNextIndex = long.MinValue;
var previousKey = new IndexEntryKey(long.MaxValue, int.MaxValue);
for (long k = 0; k < midpointsCount; ++k)
{
var nextIndex = (long)k * (count - 1) / (midpointsCount - 1);
if (previousNextIndex != nextIndex) {
ReadUntilWithMd5(PTableHeader.Size + _indexEntrySize * nextIndex, stream, md5);
stream.Read(buffer, 0, _indexKeySize);
md5.TransformBlock(buffer, 0, _indexKeySize, null, 0);
IndexEntryKey key;
if (_version == PTableVersions.Index32Bit)
{
key = new IndexEntryKey(BitConverter.ToUInt32(buffer, 4), BitConverter.ToInt32(buffer, 0));
}
else
{
key = new IndexEntryKey(BitConverter.ToUInt64(buffer, 4), BitConverter.ToInt32(buffer, 0));
}
midpoints[k] = new Midpoint(key, nextIndex);
previousNextIndex = nextIndex;
previousKey = key;
} else {
midpoints[k] = new Midpoint(previousKey, previousNextIndex);
}
}
ReadUntilWithMd5(stream.Length - MD5Size, stream, md5);
//verify hash (should be at stream.length - MD5Size)
md5.TransformFinalBlock(Empty.ByteArray, 0, 0);
var fileHash = new byte[MD5Size];
stream.Read(fileHash, 0, MD5Size);
ValidateHash(md5.Hash, fileHash);
return midpoints;
}
}
catch
{
Dispose();
throw;
}
}
#if __MonoCS__
finally
{
ReturnWorkItem(workItem);
}
#endif
}