/******************************************************************************* * 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.IO; #if AWS_ASYNC_API using System.Threading; using System.Threading.Tasks; #endif namespace Amazon.Runtime.Internal.Util { /// <summary> /// A wrapper stream. /// </summary> public class WrapperStream : Stream { /// <summary> /// Base stream. /// </summary> protected Stream BaseStream { get; private set; } /// <summary> /// Initializes WrapperStream with a base stream. /// </summary> /// <param name="baseStream"></param> public WrapperStream(Stream baseStream) { if (baseStream == null) throw new ArgumentNullException("baseStream"); BaseStream = baseStream; } /// <summary> /// Returns the first base non-WrapperStream. /// </summary> /// <returns>First base stream that is non-WrapperStream.</returns> public Stream GetNonWrapperBaseStream() { Stream baseStream = this; do { var partialStream = baseStream as PartialWrapperStream; if (partialStream != null) return partialStream; baseStream = (baseStream as WrapperStream).BaseStream; } while (baseStream is WrapperStream); return baseStream; } /// <summary> /// Returns the first base non-WrapperStream. /// </summary> /// <returns>First base stream that is non-WrapperStream.</returns> public Stream GetSeekableBaseStream() { Stream baseStream = this; do { if (baseStream.CanSeek) return baseStream; baseStream = (baseStream as WrapperStream).BaseStream; } while (baseStream is WrapperStream); if (!baseStream.CanSeek) throw new InvalidOperationException("Unable to find seekable stream"); return baseStream; } /// <summary> /// Returns the first base non-WrapperStream. /// </summary> /// <param name="stream">Potential WrapperStream</param> /// <returns>Base non-WrapperStream.</returns> public static Stream GetNonWrapperBaseStream(Stream stream) { WrapperStream wrapperStream = stream as WrapperStream; if (wrapperStream == null) return stream; return wrapperStream.GetNonWrapperBaseStream(); } public Stream SearchWrappedStream(Func<Stream, bool> condition) { Stream baseStream = this; do { if (condition(baseStream)) return baseStream; if (!(baseStream is WrapperStream)) return null; baseStream = (baseStream as WrapperStream).BaseStream; } while (baseStream != null); return baseStream; } public static Stream SearchWrappedStream(Stream stream, Func<Stream, bool> condition) { WrapperStream wrapperStream = stream as WrapperStream; if (wrapperStream == null) return condition(stream) ? stream : null; return wrapperStream.SearchWrappedStream(condition); } #region Stream overrides /// <summary> /// Gets a value indicating whether the current stream supports reading. /// True if the stream supports reading; otherwise, false. /// </summary> public override bool CanRead { get { return BaseStream.CanRead; } } /// <summary> /// Gets a value indicating whether the current stream supports seeking. /// True if the stream supports seeking; otherwise, false. /// </summary> public override bool CanSeek { get { return BaseStream.CanSeek; } } /// <summary> /// Gets a value indicating whether the current stream supports writing. /// True if the stream supports writing; otherwise, false. /// </summary> public override bool CanWrite { get { return BaseStream.CanWrite; } } /// <summary> /// Closes the current stream and releases any resources (such as sockets and /// file handles) associated with the current stream. /// </summary> #if !NETSTANDARD public override void Close() { BaseStream.Close(); } #else protected override void Dispose(bool disposing) { base.Dispose(disposing); BaseStream.Dispose(); } #endif /// <summary> /// Gets the length in bytes of the stream. /// </summary> public override long Length { get { return BaseStream.Length; } } /// <summary> /// Gets or sets the position within the current stream. /// </summary> public override long Position { get { return BaseStream.Position; } set { BaseStream.Position = value; } } /// <summary> /// Gets or sets a value, in miliseconds, that determines how long the stream /// will attempt to read before timing out. /// </summary> public override int ReadTimeout { get { return BaseStream.ReadTimeout; } set { BaseStream.ReadTimeout = value; } } /// <summary> /// Gets or sets a value, in miliseconds, that determines how long the stream /// will attempt to write before timing out. /// </summary> public override int WriteTimeout { get { return BaseStream.WriteTimeout; } set { BaseStream.WriteTimeout = value; } } /// <summary> /// Clears all buffers for this stream and causes any buffered data to be written /// to the underlying device. /// </summary> public override void Flush() { BaseStream.Flush(); } /// <summary> /// Reads a sequence of bytes from the current stream and advances the position /// within the stream by the number of bytes read. /// </summary> /// <param name="buffer"> /// 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. /// </param> /// <param name="offset"> /// The zero-based byte offset in buffer at which to begin storing the data read /// from the current stream. /// </param> /// <param name="count"> /// The maximum number of bytes to be read from the current stream. /// </param> /// <returns> /// 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. /// </returns> public override int Read(byte[] buffer, int offset, int count) { return BaseStream.Read(buffer, offset, count); } /// <summary> /// Sets the position within the current stream. /// </summary> /// <param name="offset">A byte offset relative to the origin parameter.</param> /// <param name="origin"> /// A value of type System.IO.SeekOrigin indicating the reference point used /// to obtain the new position.</param> /// <returns>The new position within the current stream.</returns> public override long Seek(long offset, SeekOrigin origin) { return BaseStream.Seek(offset, origin); } /// <summary> /// Sets the length of the current stream. /// </summary> /// <param name="value">The desired length of the current stream in bytes.</param> public override void SetLength(long value) { BaseStream.SetLength(value); } /// <summary> /// Writes a sequence of bytes to the current stream and advances the current /// position within this stream by the number of bytes written. /// </summary> /// <param name="buffer"> /// An array of bytes. This method copies count bytes from buffer to the current stream. /// </param> /// <param name="offset"> /// The zero-based byte offset in buffer at which to begin copying bytes to the /// current stream. /// </param> /// <param name="count">The number of bytes to be written to the current stream.</param> public override void Write(byte[] buffer, int offset, int count) { BaseStream.Write(buffer, offset, count); } #if AWS_ASYNC_API /// <summary> /// Asynchronously clears all buffers for this stream and causes any buffered data /// to be written to the underlying device. /// </summary> /// <param name="cancellationToken"> /// The token to monitor for cancellation requests. The default value is /// System.Threading.CancellationToken.None. /// </param> /// <returns> /// A task that represents the asynchronous flush operation. /// </returns> public override Task FlushAsync(CancellationToken cancellationToken) { return BaseStream.FlushAsync(cancellationToken); } /// <summary> /// 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. /// </summary> /// <param name="buffer"> /// 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. /// </param> /// <param name="offset"> /// The zero-based byte offset in buffer at which to begin storing the data read /// from the current stream. /// </param> /// <param name="count"> /// The maximum number of bytes to be read from the current stream. /// </param> /// <param name="cancellationToken"> /// The token to monitor for cancellation requests. The default value is /// System.Threading.CancellationToken.None. /// </param> /// <returns> /// 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. /// </returns> public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { return BaseStream.ReadAsync(buffer, offset, count, cancellationToken); } /// <summary> /// Asynchronously writes a sequence of bytes to the current stream and advances the /// current position within this stream by the number of bytes written. /// </summary> /// <param name="buffer"> /// An array of bytes. This method copies count bytes from buffer to the current stream. /// </param> /// <param name="offset"> /// The zero-based byte offset in buffer at which to begin copying bytes to the /// current stream. /// </param> /// <param name="count">The number of bytes to be written to the current stream.</param> /// <param name="cancellationToken"> /// The token to monitor for cancellation requests. The default value is /// System.Threading.CancellationToken.None. /// </param> /// <returns>A task that represents the asynchronous write operation.</returns> public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { return BaseStream.WriteAsync(buffer, offset, count, cancellationToken); } #endif #endregion internal virtual bool HasLength { get { return true; } } } }