2009-02-22 07:47:56 +00:00
|
|
|
using System;
|
|
|
|
|
using System.IO;
|
2010-02-08 01:29:31 +00:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using CUETools.Compression;
|
2009-02-22 07:47:56 +00:00
|
|
|
using ICSharpCode.SharpZipLib.Zip;
|
|
|
|
|
|
2010-02-08 01:29:31 +00:00
|
|
|
namespace CUETools.Compression.Zip
|
2009-02-22 07:47:56 +00:00
|
|
|
{
|
|
|
|
|
public class SeekableZipStream : Stream
|
|
|
|
|
{
|
|
|
|
|
ZipFile zipFile;
|
|
|
|
|
ZipEntry zipEntry;
|
|
|
|
|
Stream zipStream;
|
|
|
|
|
long position;
|
|
|
|
|
byte[] temp;
|
|
|
|
|
|
2010-02-08 01:29:31 +00:00
|
|
|
public SeekableZipStream(ZipFile file, ZipEntry entry)
|
2009-02-22 07:47:56 +00:00
|
|
|
{
|
2010-02-08 01:29:31 +00:00
|
|
|
zipFile = file;
|
|
|
|
|
zipEntry = entry;
|
2009-02-22 07:47:56 +00:00
|
|
|
zipStream = zipFile.GetInputStream(zipEntry);
|
|
|
|
|
temp = new byte[65536];
|
|
|
|
|
position = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool CanRead
|
|
|
|
|
{
|
|
|
|
|
get { return true; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool CanSeek
|
|
|
|
|
{
|
|
|
|
|
get { return true; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool CanWrite
|
|
|
|
|
{
|
|
|
|
|
get { return false; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override long Length
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return zipEntry.Size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override long Position
|
|
|
|
|
{
|
|
|
|
|
get { return position; }
|
|
|
|
|
set { Seek(value, SeekOrigin.Begin); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void Close()
|
|
|
|
|
{
|
|
|
|
|
zipEntry = null;
|
2010-02-08 01:29:31 +00:00
|
|
|
zipStream.Close();
|
2009-02-22 07:47:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void Flush()
|
|
|
|
|
{
|
|
|
|
|
throw new NotSupportedException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void SetLength(long value)
|
|
|
|
|
{
|
|
|
|
|
throw new NotSupportedException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
|
|
|
{
|
|
|
|
|
if (position == 0 && zipEntry.IsCrypted && ((ZipInputStream)zipStream).Password == null && PasswordRequired != null)
|
|
|
|
|
{
|
2010-02-08 01:29:31 +00:00
|
|
|
CompressionPasswordRequiredEventArgs e = new CompressionPasswordRequiredEventArgs();
|
2009-02-22 07:47:56 +00:00
|
|
|
PasswordRequired(this, e);
|
|
|
|
|
if (e.ContinueOperation && e.Password.Length > 0)
|
|
|
|
|
((ZipInputStream)zipStream).Password = e.Password;
|
|
|
|
|
}
|
|
|
|
|
// TODO: always save to a local temp circular buffer for optimization of the backwards seek.
|
|
|
|
|
int total = zipStream.Read(buffer, offset, count);
|
|
|
|
|
position += total;
|
|
|
|
|
if (ExtractionProgress != null)
|
|
|
|
|
{
|
2010-02-08 01:29:31 +00:00
|
|
|
CompressionExtractionProgressEventArgs e = new CompressionExtractionProgressEventArgs();
|
2009-02-22 07:47:56 +00:00
|
|
|
e.BytesExtracted = position;
|
|
|
|
|
e.FileName = zipEntry.Name;
|
|
|
|
|
e.FileSize = zipEntry.Size;
|
|
|
|
|
e.PercentComplete = 100.0 * position / zipEntry.Size;
|
|
|
|
|
ExtractionProgress(this, e);
|
|
|
|
|
}
|
|
|
|
|
return total;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
|
|
|
{
|
|
|
|
|
long seek_to;
|
|
|
|
|
switch (origin)
|
|
|
|
|
{
|
|
|
|
|
case SeekOrigin.Begin:
|
|
|
|
|
seek_to = offset;
|
|
|
|
|
break;
|
|
|
|
|
case SeekOrigin.Current:
|
|
|
|
|
seek_to = Position + offset;
|
|
|
|
|
break;
|
|
|
|
|
case SeekOrigin.End:
|
|
|
|
|
seek_to = Length + offset;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw new NotSupportedException();
|
|
|
|
|
}
|
|
|
|
|
if (seek_to < 0 || seek_to > Length)
|
|
|
|
|
throw new IOException("Invalid seek");
|
|
|
|
|
if (seek_to < position)
|
|
|
|
|
{
|
|
|
|
|
zipStream.Close();
|
|
|
|
|
zipStream = zipFile.GetInputStream(zipEntry);
|
|
|
|
|
position = 0;
|
|
|
|
|
}
|
|
|
|
|
while (seek_to > position)
|
|
|
|
|
if (Read(temp, 0, (int)Math.Min(seek_to - position, (long)temp.Length)) <= 0)
|
|
|
|
|
throw new IOException("Invalid seek");
|
|
|
|
|
return position;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void Write(byte[] array, int offset, int count)
|
|
|
|
|
{
|
|
|
|
|
throw new NotSupportedException();
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-08 01:29:31 +00:00
|
|
|
public event EventHandler<CompressionPasswordRequiredEventArgs> PasswordRequired;
|
|
|
|
|
public event EventHandler<CompressionExtractionProgressEventArgs> ExtractionProgress;
|
2009-02-22 07:47:56 +00:00
|
|
|
}
|
|
|
|
|
}
|