Files
sharpcompress/SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs

162 lines
5.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Compressor.Rar
{
internal class MultiVolumeReadOnlyStream : Stream
{
private long currentPosition;
private long maxPosition;
private IEnumerator<RarFilePart> filePartEnumerator;
private Stream currentStream;
private readonly IExtractionListener streamListener;
private long currentPartTotalReadBytes;
private long currentEntryTotalReadBytes;
internal MultiVolumeReadOnlyStream(IEnumerable<RarFilePart> parts, IExtractionListener streamListener)
{
this.streamListener = streamListener;
filePartEnumerator = parts.GetEnumerator();
filePartEnumerator.MoveNext();
InitializeNextFilePart();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
if (filePartEnumerator != null)
{
filePartEnumerator.Dispose();
filePartEnumerator = null;
}
if (currentStream != null)
{
currentStream.Dispose();
currentStream = null;
}
}
}
private void InitializeNextFilePart()
{
maxPosition = filePartEnumerator.Current.FileHeader.CompressedSize;
currentPosition = 0;
if (currentStream != null)
{
currentStream.Dispose();
}
currentStream = filePartEnumerator.Current.GetCompressedStream();
currentPartTotalReadBytes = 0;
streamListener.FireFilePartExtractionBegin(filePartEnumerator.Current.FilePartName,
filePartEnumerator.Current.FileHeader.CompressedSize,
filePartEnumerator.Current.FileHeader.UncompressedSize);
}
public override int Read(byte[] buffer, int offset, int count)
{
int totalRead = 0;
int currentOffset = offset;
int currentCount = count;
while (currentCount > 0)
{
int readSize = currentCount;
if (currentCount > maxPosition - currentPosition)
{
readSize = (int) (maxPosition - currentPosition);
}
int read = currentStream.Read(buffer, currentOffset, readSize);
if (read < 0)
{
throw new EndOfStreamException();
}
currentPosition += read;
currentOffset += read;
currentCount -= read;
totalRead += read;
if (((maxPosition - currentPosition) == 0)
&& filePartEnumerator.Current.FileHeader.FileFlags.HasFlag(FileFlags.SPLIT_AFTER))
{
if (filePartEnumerator.Current.FileHeader.Salt != null)
{
throw new InvalidFormatException("Sharpcompress currently does not support multi-volume decryption.");
}
string fileName = filePartEnumerator.Current.FileHeader.FileName;
if (!filePartEnumerator.MoveNext())
{
throw new InvalidFormatException(
"Multi-part rar file is incomplete. Entry expects a new volume: " + fileName);
}
InitializeNextFilePart();
}
else
{
break;
}
}
currentPartTotalReadBytes += totalRead;
currentEntryTotalReadBytes += totalRead;
streamListener.FireCompressedBytesRead(currentPartTotalReadBytes, currentEntryTotalReadBytes);
return totalRead;
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
throw new NotImplementedException();
}
public override long Length
{
get { throw new NotImplementedException(); }
}
public override long Position
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}
}