mirror of https://github.com/SixLabors/ImageSharp
8 changed files with 641 additions and 4 deletions
@ -0,0 +1,60 @@ |
|||
// <copyright file="DeflateTiffCompression.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Formats.Tiff |
|||
{ |
|||
using System; |
|||
using System.Buffers; |
|||
using System.IO; |
|||
using System.IO.Compression; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// Class to handle cases where TIFF image data is compressed using Deflate compression.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Note that the 'OldDeflate' compression type is identical to the 'Deflate' compression type.
|
|||
/// </remarks>
|
|||
internal static class DeflateTiffCompression |
|||
{ |
|||
/// <summary>
|
|||
/// Decompresses image data into the supplied buffer.
|
|||
/// </summary>
|
|||
/// <param name="stream">The <see cref="Stream"/> to read image data from.</param>
|
|||
/// <param name="byteCount">The number of bytes to read from the input stream.</param>
|
|||
/// <param name="buffer">The output buffer for uncompressed data.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static void Decompress(Stream stream, int byteCount, byte[] buffer) |
|||
{ |
|||
// Read the 'zlib' header information
|
|||
int cmf = stream.ReadByte(); |
|||
int flag = stream.ReadByte(); |
|||
|
|||
if ((cmf & 0x0f) != 8) |
|||
{ |
|||
throw new Exception($"Bad compression method for ZLIB header: cmf={cmf}"); |
|||
} |
|||
|
|||
// If the 'fdict' flag is set then we should skip the next four bytes
|
|||
bool fdict = (flag & 32) != 0; |
|||
|
|||
if (fdict) |
|||
{ |
|||
stream.ReadByte(); |
|||
stream.ReadByte(); |
|||
stream.ReadByte(); |
|||
stream.ReadByte(); |
|||
} |
|||
|
|||
// The subsequent data is the Deflate compressed data (except for the last four bytes of checksum)
|
|||
int headerLength = fdict ? 10 : 6; |
|||
SubStream subStream = new SubStream(stream, byteCount - headerLength); |
|||
using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress, true)) |
|||
{ |
|||
deflateStream.ReadFull(buffer); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,177 @@ |
|||
// <copyright file="SubStream.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
namespace ImageSharp.Formats.Tiff |
|||
{ |
|||
using System; |
|||
using System.IO; |
|||
|
|||
/// <summary>
|
|||
/// Utility class to encapsulate a sub-portion of another <see cref="Stream"/>.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Note that disposing of the <see cref="SubStream"/> does not dispose the underlying
|
|||
/// <see cref="Stream"/>.
|
|||
/// </remarks>
|
|||
internal class SubStream : Stream |
|||
{ |
|||
private Stream innerStream; |
|||
private long offset; |
|||
private long endOffset; |
|||
private long length; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Stream"/> class.
|
|||
/// </summary>
|
|||
/// <param name="innerStream">The underlying <see cref="Stream"/> to wrap.</param>
|
|||
/// <param name="length">The length of the sub-stream.</param>
|
|||
/// <remarks>
|
|||
/// Note that calling the sub-stream with start from the current offset of the
|
|||
/// underlying <see cref="Stream"/>
|
|||
/// </remarks>
|
|||
public SubStream(Stream innerStream, long length) |
|||
{ |
|||
this.innerStream = innerStream; |
|||
this.offset = this.innerStream.Position; |
|||
this.endOffset = this.offset + length; |
|||
this.length = length; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Stream"/> class.
|
|||
/// </summary>
|
|||
/// <param name="innerStream">The underlying <see cref="Stream"/> to wrap.</param>
|
|||
/// <param name="offset">The offset of the sub-stream within the underlying <see cref="Stream"/>.</param>
|
|||
/// <param name="length">The length of the sub-stream.</param>
|
|||
/// <remarks>
|
|||
/// Note that calling the constructor will immediately move the underlying
|
|||
/// <see cref="Stream"/> to the specified offset.
|
|||
/// </remarks>
|
|||
public SubStream(Stream innerStream, long offset, long length) |
|||
{ |
|||
this.innerStream = innerStream; |
|||
this.offset = offset; |
|||
this.endOffset = offset + length; |
|||
this.length = length; |
|||
|
|||
innerStream.Seek(offset, SeekOrigin.Begin); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool CanRead |
|||
{ |
|||
get |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool CanWrite |
|||
{ |
|||
get |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool CanSeek |
|||
{ |
|||
get |
|||
{ |
|||
return this.innerStream.CanSeek; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override long Length |
|||
{ |
|||
get |
|||
{ |
|||
return this.length; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override long Position |
|||
{ |
|||
get |
|||
{ |
|||
return this.innerStream.Position - this.offset; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.Seek(value, SeekOrigin.Begin); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void Flush() |
|||
{ |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int Read(byte[] buffer, int offset, int count) |
|||
{ |
|||
long bytesRemaining = this.endOffset - this.innerStream.Position; |
|||
|
|||
if (bytesRemaining < count) |
|||
{ |
|||
count = (int)bytesRemaining; |
|||
} |
|||
|
|||
return this.innerStream.Read(buffer, offset, count); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int ReadByte() |
|||
{ |
|||
if (this.innerStream.Position < this.endOffset) |
|||
{ |
|||
return this.innerStream.ReadByte(); |
|||
} |
|||
else |
|||
{ |
|||
return -1; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void Write(byte[] array, int offset, int count) |
|||
{ |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void WriteByte(byte value) |
|||
{ |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override long Seek(long offset, SeekOrigin origin) |
|||
{ |
|||
switch (origin) |
|||
{ |
|||
case SeekOrigin.Current: |
|||
return this.innerStream.Seek(offset, SeekOrigin.Current) - this.offset; |
|||
case SeekOrigin.Begin: |
|||
return this.innerStream.Seek(this.offset + offset, SeekOrigin.Begin) - this.offset; |
|||
case SeekOrigin.End: |
|||
return this.innerStream.Seek(this.endOffset - offset, SeekOrigin.Begin) - this.offset; |
|||
default: |
|||
throw new ArgumentException("Invalid seek origin."); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void SetLength(long value) |
|||
{ |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
// <copyright file="DeflateTiffCompressionTests.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Tests |
|||
{ |
|||
using System.IO; |
|||
using Xunit; |
|||
|
|||
using ImageSharp.Formats; |
|||
using ImageSharp.Formats.Tiff; |
|||
|
|||
public class DeflateTiffCompressionTests |
|||
{ |
|||
[Theory] |
|||
[InlineData(new byte[] { })] |
|||
[InlineData(new byte[] { 42 })] // One byte
|
|||
[InlineData(new byte[] { 42, 16, 128, 53, 96, 218, 7, 64, 3, 4, 97 })] // Random bytes
|
|||
[InlineData(new byte[] { 1, 2, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 3, 4 })] // Repeated bytes
|
|||
[InlineData(new byte[] { 1, 2, 42, 53, 42, 53, 42, 53, 42, 53, 42, 53, 3, 4 })] // Repeated sequence
|
|||
public void Decompress_ReadsData(byte[] data) |
|||
{ |
|||
using (Stream stream = CreateCompressedStream(data)) |
|||
{ |
|||
byte[] buffer = new byte[data.Length]; |
|||
|
|||
DeflateTiffCompression.Decompress(stream, data.Length, buffer); |
|||
|
|||
Assert.Equal(data, buffer); |
|||
} |
|||
} |
|||
|
|||
private static Stream CreateCompressedStream(byte[] data) |
|||
{ |
|||
Stream compressedStream = new MemoryStream(); |
|||
|
|||
using (Stream uncompressedStream = new MemoryStream(data), |
|||
deflateStream = new ZlibDeflateStream(compressedStream, 6)) |
|||
{ |
|||
uncompressedStream.CopyTo(deflateStream); |
|||
} |
|||
|
|||
compressedStream.Seek(0, SeekOrigin.Begin); |
|||
return compressedStream; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,327 @@ |
|||
// <copyright file="SubStreamTests.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Tests |
|||
{ |
|||
using System; |
|||
using System.IO; |
|||
using Xunit; |
|||
|
|||
using ImageSharp.Formats.Tiff; |
|||
|
|||
public class SubStreamTests |
|||
{ |
|||
[Fact] |
|||
public void Constructor_PositionsStreamCorrectly_WithSpecifiedOffset() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
innerStream.Position = 2; |
|||
|
|||
SubStream stream = new SubStream(innerStream, 4, 6); |
|||
|
|||
Assert.Equal(0, stream.Position); |
|||
Assert.Equal(6, stream.Length); |
|||
Assert.Equal(4, innerStream.Position); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Constructor_PositionsStreamCorrectly_WithCurrentOffset() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
innerStream.Position = 2; |
|||
|
|||
SubStream stream = new SubStream(innerStream, 6); |
|||
|
|||
Assert.Equal(0, stream.Position); |
|||
Assert.Equal(6, stream.Length); |
|||
Assert.Equal(2, innerStream.Position); |
|||
} |
|||
|
|||
[Fact] |
|||
public void CanRead_ReturnsTrue() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
Assert.True(stream.CanRead); |
|||
} |
|||
|
|||
[Fact] |
|||
public void CanWrite_ReturnsFalse() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
Assert.False(stream.CanWrite); |
|||
} |
|||
|
|||
[Fact] |
|||
public void CanSeek_ReturnsTrue() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
Assert.True(stream.CanSeek); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Length_ReturnsTheConstrainedLength() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
Assert.Equal(6, stream.Length); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Position_ReturnsZeroBeforeReading() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
Assert.Equal(0, stream.Position); |
|||
Assert.Equal(2, innerStream.Position); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Position_ReturnsPositionAfterReading() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Read(new byte[2], 0, 2); |
|||
|
|||
Assert.Equal(2, stream.Position); |
|||
Assert.Equal(4, innerStream.Position); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Position_ReturnsPositionAfterReadingTwice() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Read(new byte[2], 0, 2); |
|||
stream.Read(new byte[2], 0, 2); |
|||
|
|||
Assert.Equal(4, stream.Position); |
|||
Assert.Equal(6, innerStream.Position); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Position_SettingPropertySeeksToNewPosition() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Position = 3; |
|||
|
|||
Assert.Equal(3, stream.Position); |
|||
Assert.Equal(5, innerStream.Position); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Flush_ThrowsNotSupportedException() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
Assert.Throws<NotSupportedException>(() => stream.Flush()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Read_Reads_FromStartOfSubStream() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
byte[] buffer = new byte[3]; |
|||
var result = stream.Read(buffer, 0, 3); |
|||
|
|||
Assert.Equal(new byte[] { 3, 4, 5 }, buffer); |
|||
Assert.Equal(3, result); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(2, SeekOrigin.Begin)] |
|||
[InlineData(1, SeekOrigin.Current)] |
|||
[InlineData(4, SeekOrigin.End)] |
|||
public void Read_Reads_FromMiddleOfSubStream(long offset, SeekOrigin origin) |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Position = 1; |
|||
stream.Seek(offset, origin); |
|||
byte[] buffer = new byte[3]; |
|||
var result = stream.Read(buffer, 0, 3); |
|||
|
|||
Assert.Equal(new byte[] { 5, 6, 7 }, buffer); |
|||
Assert.Equal(3, result); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(3, SeekOrigin.Begin)] |
|||
[InlineData(2, SeekOrigin.Current)] |
|||
[InlineData(3, SeekOrigin.End)] |
|||
public void Read_Reads_FromEndOfSubStream(long offset, SeekOrigin origin) |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Position = 1; |
|||
stream.Seek(offset, origin); |
|||
byte[] buffer = new byte[3]; |
|||
var result = stream.Read(buffer, 0, 3); |
|||
|
|||
Assert.Equal(new byte[] { 6, 7, 8 }, buffer); |
|||
Assert.Equal(3, result); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(4, SeekOrigin.Begin)] |
|||
[InlineData(3, SeekOrigin.Current)] |
|||
[InlineData(2, SeekOrigin.End)] |
|||
public void Read_Reads_FromBeyondEndOfSubStream(long offset, SeekOrigin origin) |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Position = 1; |
|||
stream.Seek(offset, origin); |
|||
byte[] buffer = new byte[3]; |
|||
var result = stream.Read(buffer, 0, 3); |
|||
|
|||
Assert.Equal(new byte[] { 7, 8, 0 }, buffer); |
|||
Assert.Equal(2, result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ReadByte_Reads_FromStartOfSubStream() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
var result = stream.ReadByte(); |
|||
|
|||
Assert.Equal(3, result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ReadByte_Reads_FromMiddleOfSubStream() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Position = 3; |
|||
var result = stream.ReadByte(); |
|||
|
|||
Assert.Equal(6, result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ReadByte_Reads_FromEndOfSubStream() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Position = 5; |
|||
var result = stream.ReadByte(); |
|||
|
|||
Assert.Equal(8, result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ReadByte_Reads_FromBeyondEndOfSubStream() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Position = 5; |
|||
stream.ReadByte(); |
|||
var result = stream.ReadByte(); |
|||
|
|||
Assert.Equal(-1, result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Write_ThrowsNotSupportedException() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
Assert.Throws<NotSupportedException>(() => stream.Write(new byte[] { 1, 2 }, 0, 2)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void WriteByte_ThrowsNotSupportedException() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
Assert.Throws<NotSupportedException>(() => stream.WriteByte(42)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Seek_MovesToNewPosition_FromBegin() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Position = 1; |
|||
long result = stream.Seek(2, SeekOrigin.Begin); |
|||
|
|||
Assert.Equal(2, result); |
|||
Assert.Equal(2, stream.Position); |
|||
Assert.Equal(4, innerStream.Position); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Seek_MovesToNewPosition_FromCurrent() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Position = 1; |
|||
long result = stream.Seek(2, SeekOrigin.Current); |
|||
|
|||
Assert.Equal(3, result); |
|||
Assert.Equal(3, stream.Position); |
|||
Assert.Equal(5, innerStream.Position); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Seek_MovesToNewPosition_FromEnd() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
stream.Position = 1; |
|||
long result = stream.Seek(2, SeekOrigin.End); |
|||
|
|||
Assert.Equal(4, result); |
|||
Assert.Equal(4, stream.Position); |
|||
Assert.Equal(6, innerStream.Position); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Seek_ThrowsException_WithInvalidOrigin() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
var e = Assert.Throws<ArgumentException>(() => stream.Seek(2, (SeekOrigin)99)); |
|||
Assert.Equal("Invalid seek origin.", e.Message); |
|||
} |
|||
|
|||
public void SetLength_ThrowsNotSupportedException() |
|||
{ |
|||
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); |
|||
SubStream stream = new SubStream(innerStream, 2, 6); |
|||
|
|||
Assert.Throws<NotSupportedException>(() => stream.SetLength(5)); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue