diff --git a/src/cs-S3Zip.Tests/S3ZipTests.cs b/src/cs-S3Zip.Tests/S3ZipTests.cs index 76e07ddfcad991b45d4a06bf73348bb1ba0ae789..7984204697dcde2526b23d9e351987e1c9ad0f81 100644 --- a/src/cs-S3Zip.Tests/S3ZipTests.cs +++ b/src/cs-S3Zip.Tests/S3ZipTests.cs @@ -56,7 +56,7 @@ namespace coscine.cs_S3Zip.Tests var zipUtilities = new ZipUtilities(_s3MultipartStreamConfiguration); using (var s3MultipartDownloadStream = new S3MultipartDownloadStream(key, _s3MultipartStreamConfiguration)) { - using (var archive = new ZipArchive(s3MultipartDownloadStream, ZipArchiveMode.Read, true)) + using (var archive = new ZipArchive(s3MultipartDownloadStream, ZipArchiveMode.Read)) { zipUtilities.UnzipToFolder(archive, @"c:\temp\test2\"); } diff --git a/src/cs-S3Zip/S3MultipartDownloadStream.cs b/src/cs-S3Zip/S3MultipartDownloadStream.cs index f09325977327fab192055371b343dddddd6b2cb5..2b134032f1ffd8a88bad8dcc65cc227b5e2171e9 100644 --- a/src/cs-S3Zip/S3MultipartDownloadStream.cs +++ b/src/cs-S3Zip/S3MultipartDownloadStream.cs @@ -17,7 +17,7 @@ namespace coscine.cs_S3Zip public override bool CanRead => true; - public override bool CanSeek => false; + public override bool CanSeek => true; public override bool CanWrite => false; @@ -54,26 +54,15 @@ namespace coscine.cs_S3Zip } - private void DownloadCurrentPart() - { - if (Position < Length) - { - DownloadPart(_part); - _part++; - } - } - - private void DownloadPart(int part) + private void DownloadRange(ByteRange range) { - _position += _internalStream.Position; - using (var client = new AmazonS3Client(S3MultipartStreamConfiguration.AccessKey, S3MultipartStreamConfiguration.SecretKey, S3MultipartStreamConfiguration.AmazonS3Config)) { var request = new GetObjectRequest { BucketName = S3MultipartStreamConfiguration.BucketName, Key = Key, - ByteRange = new ByteRange(part * S3MultipartStreamConfiguration.ChunckSize, (part + 1) * S3MultipartStreamConfiguration.ChunckSize - 1) + ByteRange = range }; _internalStream.SetLength(0); @@ -84,7 +73,22 @@ namespace coscine.cs_S3Zip } } - _internalStream.Position = 0; + _internalStream.Position = 0; + } + + private void DownloadCurrentPart() + { + if (Position < Length) + { + DownloadPart(_part); + _part++; + } + } + + private void DownloadPart(int part) + { + _position += _internalStream.Position; + DownloadRange(new ByteRange(part * S3MultipartStreamConfiguration.ChunckSize, (part + 1) * S3MultipartStreamConfiguration.ChunckSize - 1)); } public override void Flush() @@ -114,9 +118,67 @@ namespace coscine.cs_S3Zip return read; } + + private ByteRange CalculateByteRange(long position) + { + long leftPosition; + long rightPosition; + + if (position - (S3MultipartStreamConfiguration.ChunckSize / 2) < 0 + && position + (S3MultipartStreamConfiguration.ChunckSize / 2) + S3MultipartStreamConfiguration.ChunckSize % 2 - 1 >= Length) + { + // both to small + leftPosition = 0; + rightPosition = Length - 1; + } + else if (position - (S3MultipartStreamConfiguration.ChunckSize / 2) < 0) + { + // left to small + leftPosition = 0; + rightPosition = S3MultipartStreamConfiguration.ChunckSize - 1; + } + else if (position + (S3MultipartStreamConfiguration.ChunckSize / 2) + S3MultipartStreamConfiguration.ChunckSize % 2 - 1 >= Length) + { + // right to small + leftPosition = Length - S3MultipartStreamConfiguration.ChunckSize - 1; + rightPosition = Length - 1; + } + else + { + // fits perfectly + leftPosition = position - (S3MultipartStreamConfiguration.ChunckSize / 2); + rightPosition = position + (S3MultipartStreamConfiguration.ChunckSize / 2) + S3MultipartStreamConfiguration.ChunckSize % 2 - 1; + } + + return new ByteRange(leftPosition, rightPosition); + } + + public override long Seek(long offset, SeekOrigin origin) { - throw new System.NotImplementedException(); + switch (origin) + { + case SeekOrigin.Begin: + DownloadRange(CalculateByteRange(offset)); + _position = offset; + break; + case SeekOrigin.Current: + if (Position + offset > _position + _internalStream.Length || Position + offset < _position) + { + DownloadRange(CalculateByteRange(Position + offset)); + _position = Position + offset; + } else + { + _internalStream.Position += offset; + } + break; + case SeekOrigin.End: + DownloadRange(CalculateByteRange(_length - 1 + offset)); + _position = _length - 1 + offset; + break; + } + + return Position; } public override void SetLength(long value)