using System;
using System.IO;
namespace Shared.Util
{
/// <summary>
/// A wrapper around another stream that adds a prefix and postfix
/// to the content of the stream.
/// </summary>
public class WrapperStream : Stream
{
/// <summary>
/// The prefix position.
/// </summary>
private int prefixPosition;
/// <summary>
/// The prefix (readonly).
/// </summary>
private readonly string Prefix;
/// <summary>
/// The wrapped stream (readonly).
/// </summary>
private readonly Stream WrappedStream;
/// <summary>
/// The postfix position.
/// </summary>
private int postfixPosition;
/// <summary>
/// The postfix (readonly).
/// </summary>
private readonly string Postfix;
/// <summary>
/// Gets a value indicating whether
/// </summary>
public override bool CanRead => true;
/// <summary>
/// Gets a value indicating whether
/// </summary>
public override bool CanSeek => false;
/// <summary>
/// Gets a value indicating whether
/// </summary>
public override bool CanWrite => false;
/// <summary>
/// Gets the length.
/// </summary>
public override long Length => throw new NotSupportedException();
/// <summary>
/// Gets or sets the position.
/// </summary>
public override long Position { get => prefixPosition + WrappedStream.Position + postfixPosition; set => throw new NotSupportedException(); }
/// <summary>
/// Initializes a new instance of the <see cref="WrapperStream"/> class.
/// </summary>
/// <param name="prefix">The prefix.</param>
/// <param name="wrappedStream">The wrappedStream.</param>
/// <param name="postfix">The postfix.</param>
/// <exception cref="ArgumentException">The wrappedstream, prefix or postfix cannot be null</exception>
/// <exception cref="ArgumentException">Must be able to read from the wrapped stream</exception>
public WrapperStream(string prefix, Stream wrappedStream, string postfix)
{
Prefix = prefix;
Postfix = postfix;
WrappedStream = wrappedStream;
if (wrappedStream == null || prefix == null || postfix == null)
{
throw new ArgumentException("The wrappedstream, prefix or postfix cannot be null");
}
if (!wrappedStream.CanRead)
{
throw new ArgumentException("Must be able to read from the wrapped stream");
}
}
/// <summary>
/// The flush.
/// </summary>
public override void Flush()
{
prefixPosition = 0;
postfixPosition = 0;
WrappedStream.Flush();
}
/// <summary>
/// The seek.
/// </summary>
/// <param name="offset">The offset.</param>
/// <param name="origin">The origin.</param>
/// <returns>The <see cref="long"/>.</returns>
/// <exception cref="NotSupportedException"></exception>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
/// <summary>
/// Set the length.
/// </summary>
/// <param name="value">The value.</param>
/// <exception cref="NotSupportedException"></exception>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
/// <summary>
/// Read.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The offset.</param>
/// <param name="count">The count.</param>
/// <returns>The <see cref="int"/>.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
int readBytes = 0;
// If bytes need to be read from the prefix set those bytes in the buffer
for (; readBytes < count && prefixPosition < Prefix.Length; ++readBytes)
{
buffer[offset + readBytes] = (byte)Prefix[prefixPosition++];
}
// If bytes need to be read from the wrapped stream read them
if (readBytes < count)
{
readBytes += WrappedStream.Read(buffer, offset + readBytes, count - readBytes);
}
// If we still need to read bytes but can't read them from the wrapped
// stream object read them from the postfix. There is no real way to
// know when there are no bytes anymore in the WrappedStream object
// unless reading from it returns a 0.
if (readBytes == 0 && postfixPosition < Postfix.Length)
{
for (; readBytes < count && postfixPosition < Postfix.Length; ++readBytes)
{
buffer[offset + readBytes] = (byte)Postfix[postfixPosition++];
}
}
return readBytes;
}
/// <summary>
/// Write.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The offset.</param>
/// <param name="count">The count.</param>
/// <exception cref="NotSupportedException"></exception>
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
}
}
Comments