mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-11-15 17:02:03 +00:00
Release owned Squeeze buffers and failed PPMd models
This commit is contained in:
@@ -28,7 +28,16 @@ public class PpmdStream : Stream, IAsyncDisposable
|
||||
_stream = stream;
|
||||
_compress = compress;
|
||||
|
||||
InitializeSync(stream, compress);
|
||||
try
|
||||
{
|
||||
InitializeSync(stream, compress);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Construction has not transferred ownership to a caller yet.
|
||||
_modelH?.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private PpmdStream(
|
||||
@@ -47,6 +56,13 @@ public class PpmdStream : Stream, IAsyncDisposable
|
||||
|
||||
private void InitializeSync(Stream stream, bool compress)
|
||||
{
|
||||
if (
|
||||
compress
|
||||
&& (_properties.Version == PpmdVersion.H || _properties.Version == PpmdVersion.H7Z)
|
||||
)
|
||||
{
|
||||
throw new NotImplementedException("PPMd H/H7Z compression not supported");
|
||||
}
|
||||
if (_properties.Version == PpmdVersion.I1)
|
||||
{
|
||||
_model = new Model();
|
||||
@@ -62,19 +78,11 @@ public class PpmdStream : Stream, IAsyncDisposable
|
||||
if (_properties.Version == PpmdVersion.H)
|
||||
{
|
||||
_modelH = new ModelPpm();
|
||||
if (compress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
_modelH.DecodeInit(stream, _properties.ModelOrder, _properties.AllocatorSize);
|
||||
}
|
||||
if (_properties.Version == PpmdVersion.H7Z)
|
||||
{
|
||||
_modelH = new ModelPpm();
|
||||
if (compress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
_modelH.DecodeInit(null, _properties.ModelOrder, _properties.AllocatorSize);
|
||||
_decoder = new Decoder();
|
||||
_decoder.Init(stream);
|
||||
|
||||
@@ -17,11 +17,20 @@ public partial class SqueezeStream
|
||||
)
|
||||
{
|
||||
var squeezeStream = new SqueezeStream(stream, compressedSize);
|
||||
squeezeStream._decodedStream = await squeezeStream
|
||||
.BuildDecodedStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return squeezeStream;
|
||||
try
|
||||
{
|
||||
squeezeStream._decodedStream = await squeezeStream
|
||||
.BuildDecodedStreamAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return squeezeStream;
|
||||
}
|
||||
catch
|
||||
{
|
||||
#pragma warning disable VSTHRD103 // Cleanup only releases in-memory buffers; the source remains open.
|
||||
squeezeStream.Dispose();
|
||||
#pragma warning restore VSTHRD103
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<int> ReadAsync(
|
||||
@@ -83,7 +92,7 @@ public partial class SqueezeStream
|
||||
}
|
||||
|
||||
var bitReader = new BitReader(_stream);
|
||||
var huffmanDecoded = new PooledMemoryStream();
|
||||
var huffmanDecoded = _huffmanDecoded = new PooledMemoryStream();
|
||||
int i = 0;
|
||||
|
||||
while (true)
|
||||
|
||||
@@ -16,6 +16,7 @@ public partial class SqueezeStream : Stream
|
||||
private const int SPEOF = 256;
|
||||
|
||||
private Stream _decodedStream = null!;
|
||||
private PooledMemoryStream? _huffmanDecoded;
|
||||
|
||||
private SqueezeStream(Stream stream, int compressedSize)
|
||||
{
|
||||
@@ -25,15 +26,36 @@ public partial class SqueezeStream : Stream
|
||||
public static SqueezeStream Create(Stream stream, int compressedSize)
|
||||
{
|
||||
var squeezeStream = new SqueezeStream(stream, compressedSize);
|
||||
squeezeStream._decodedStream = squeezeStream.BuildDecodedStream();
|
||||
|
||||
return squeezeStream;
|
||||
try
|
||||
{
|
||||
squeezeStream._decodedStream = squeezeStream.BuildDecodedStream();
|
||||
return squeezeStream;
|
||||
}
|
||||
catch
|
||||
{
|
||||
squeezeStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_decodedStream?.Dispose();
|
||||
base.Dispose(disposing);
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_decodedStream?.Dispose();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// RunLength90Stream deliberately does not own its input.
|
||||
_huffmanDecoded?.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanRead => true;
|
||||
@@ -79,7 +101,7 @@ public partial class SqueezeStream : Stream
|
||||
}
|
||||
|
||||
var bitReader = new BitReader(_stream);
|
||||
var huffmanDecoded = new PooledMemoryStream();
|
||||
var huffmanDecoded = _huffmanDecoded = new PooledMemoryStream();
|
||||
int i = 0;
|
||||
|
||||
while (true)
|
||||
|
||||
42
tests/SharpCompress.Test/Streams/SqueezeLifetimeTests.cs
Normal file
42
tests/SharpCompress.Test/Streams/SqueezeLifetimeTests.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.PPMd;
|
||||
using SharpCompress.Compressors.Squeezed;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Streams;
|
||||
|
||||
public class SqueezeLifetimeTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async Task DisposeReleasesOwnedHuffmanStream(bool asyncOpen)
|
||||
{
|
||||
// One Huffman node: literal A on zero, end marker on one.
|
||||
using var source = new MemoryStream(new byte[] { 1, 0, 190, 255, 255, 254, 2 });
|
||||
var stream = asyncOpen
|
||||
? await SqueezeStream.CreateAsync(source, 7, CancellationToken.None)
|
||||
: SqueezeStream.Create(source, 7);
|
||||
var owned = (Stream)
|
||||
typeof(SqueezeStream)
|
||||
.GetField("_huffmanDecoded", BindingFlags.Instance | BindingFlags.NonPublic)!
|
||||
.GetValue(stream)!;
|
||||
Assert.True(owned.CanRead);
|
||||
stream.Dispose();
|
||||
Assert.False(owned.CanRead);
|
||||
Assert.True(source.CanRead);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnsupportedPpmdCompressionLeavesInputOpen()
|
||||
{
|
||||
using var source = new MemoryStream();
|
||||
var properties = new PpmdProperties(new byte[] { 2, 0, 0, 16, 0 });
|
||||
Assert.Throws<NotImplementedException>(() => PpmdStream.Create(properties, source, true));
|
||||
Assert.True(source.CanRead);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user