/*******************************************************************************
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use
* this file except in compliance with the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file.
* This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
* *****************************************************************************
* __ _ _ ___
* ( )( \/\/ )/ __)
* /__\ \ / \__ \
* (_)(_) \/\/ (___/
*
* AWS SDK for .NET
* API Version: 2006-03-01
*
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
#if AWS_ASYNC_API
using System.Threading;
using System.Threading.Tasks;
#endif
namespace Amazon.Runtime.Internal.Util
{
///
/// This class is used to wrap a stream for a particular segment of a stream. It
/// makes that segment look like you are reading from beginning to end of the stream.
///
public class PartialWrapperStream : WrapperStream
{
private long initialPosition;
private long partSize;
public PartialWrapperStream(Stream stream, long partSize)
: base(stream)
{
if (!stream.CanSeek)
throw new InvalidOperationException("Base stream of PartialWrapperStream must be seekable");
this.initialPosition = stream.Position;
long remainingData = stream.Length - stream.Position;
if (partSize == 0 || remainingData < partSize)
{
this.partSize = remainingData;
}
else
{
this.partSize = partSize;
var encryptionStream = BaseStream as AESEncryptionUploadPartStream;
if (encryptionStream != null && (partSize % 16) != 0)
{
this.partSize = partSize - (partSize % EncryptUploadPartStream.InternalEncryptionBlockSize);
}
}
}
private long RemainingPartSize
{
get
{
long remaining = this.partSize - this.Position;
return remaining;
}
}
#region Stream overrides
public override long Length
{
get
{
long length = base.Length - this.initialPosition;
if (length > this.partSize)
{
length = this.partSize;
}
return length;
}
}
public override long Position
{
get
{
return base.Position - this.initialPosition;
}
set
{
base.Position = this.initialPosition + value;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
int bytesToRead = count < this.RemainingPartSize ? count : (int)this.RemainingPartSize;
if (bytesToRead <= 0)
return 0;
return base.Read(buffer, offset, bytesToRead);
}
public override long Seek(long offset, SeekOrigin origin)
{
long position = 0;
switch (origin)
{
case SeekOrigin.Begin:
position = this.initialPosition + offset;
break;
case SeekOrigin.Current:
position = base.Position + offset;
break;
case SeekOrigin.End:
position = base.Position + this.partSize + offset;
break;
}
if (position < this.initialPosition)
{
position = this.initialPosition;
}
else if (position > this.initialPosition + this.partSize)
{
position = this.initialPosition + this.partSize;
}
base.Position = position;
return this.Position;
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override void WriteByte(byte value)
{
throw new NotSupportedException();
}
#if AWS_ASYNC_API
///
/// Asynchronously reads a sequence of bytes from the current stream, advances
/// the position within the stream by the number of bytes read, and monitors
/// cancellation requests.
///
///
/// An array of bytes. When this method returns, the buffer contains the specified
/// byte array with the values between offset and (offset + count - 1) replaced
/// by the bytes read from the current source.
///
///
/// The zero-based byte offset in buffer at which to begin storing the data read
/// from the current stream.
///
///
/// The maximum number of bytes to be read from the current stream.
///
///
/// The token to monitor for cancellation requests. The default value is
/// System.Threading.CancellationToken.None.
///
///
/// A task that represents the asynchronous read operation. The value of the TResult
/// parameter contains the total number of bytes read into the buffer. This can be
/// less than the number of bytes requested if that many bytes are not currently
/// available, or zero (0) if the end of the stream has been reached.
///
public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
int bytesToRead = count < this.RemainingPartSize ? count : (int)this.RemainingPartSize;
if (bytesToRead <= 0)
return 0;
return await base.ReadAsync(buffer, offset, bytesToRead, cancellationToken).ConfigureAwait(false);
}
///
/// Asynchronously writes a sequence of bytes to the current stream and advances the
/// current position within this stream by the number of bytes written.
///
///
/// An array of bytes. This method copies count bytes from buffer to the current stream.
///
///
/// The zero-based byte offset in buffer at which to begin copying bytes to the
/// current stream.
///
/// The number of bytes to be written to the current stream.
///
/// The token to monitor for cancellation requests. The default value is
/// System.Threading.CancellationToken.None.
///
/// A task that represents the asynchronous write operation.
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
throw new NotSupportedException();
}
#endif
#if !NETSTANDARD
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, Object state)
{
throw new NotSupportedException();
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, Object state)
{
throw new NotSupportedException();
}
public override int EndRead(IAsyncResult asyncResult)
{
throw new NotImplementedException();
}
public override void EndWrite(IAsyncResult asyncResult)
{
throw new NotImplementedException();
}
#endif
#endregion
}
}