LZMA create

This commit is contained in:
Adam Hathcock
2026-01-22 17:01:48 +00:00
parent 11b92d102a
commit 44402414a6
10 changed files with 105 additions and 78 deletions

View File

@@ -200,7 +200,7 @@ internal abstract partial class ZipFilePart
await stream
.ReadFullyAsync(props, 0, propsSize, cancellationToken)
.ConfigureAwait(false);
return new LzmaStream(
return LzmaStream.Create(
props,
stream,
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,

View File

@@ -134,7 +134,7 @@ internal abstract partial class ZipFilePart : FilePart
reader.ReadUInt16(); //LZMA version
var props = new byte[reader.ReadUInt16()];
reader.Read(props, 0, props.Length);
return new LzmaStream(
return LzmaStream.Create(
props,
stream,
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,

View File

@@ -62,7 +62,7 @@ public sealed partial class LZipStream : Stream, IStreamStack
throw new InvalidFormatException("Not an LZip stream");
}
var properties = GetProperties(dSize);
_stream = new LzmaStream(properties, stream, leaveOpen: leaveOpen);
_stream = LzmaStream.Create(properties, stream, leaveOpen: leaveOpen);
}
else
{
@@ -72,9 +72,10 @@ public sealed partial class LZipStream : Stream, IStreamStack
_countingWritableSubStream = new SharpCompressStream(stream, leaveOpen: true);
_stream = new Crc32Stream(
new LzmaStream(
LzmaStream.Create(
new LzmaEncoderProperties(true, dSize),
false,
null,
_countingWritableSubStream
)
);

View File

@@ -1,4 +1,3 @@
#nullable disable
using System;
using System.Buffers.Binary;
@@ -17,7 +16,7 @@ public partial class LzmaStream : Stream, IStreamStack
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _inputStream;
Stream IStreamStack.BaseStream() => _inputStream!;
int IStreamStack.BufferSize
{
@@ -32,7 +31,7 @@ public partial class LzmaStream : Stream, IStreamStack
void IStreamStack.SetPosition(long position) { }
private readonly Stream _inputStream;
private readonly Stream? _inputStream;
private readonly long _inputSize;
private readonly long _outputSize;
private readonly bool _leaveOpen;
@@ -40,7 +39,7 @@ public partial class LzmaStream : Stream, IStreamStack
private readonly int _dictionarySize;
private readonly OutWindow _outWindow = new();
private readonly RangeCoder.Decoder _rangeDecoder = new();
private Decoder _decoder;
private Decoder? _decoder;
private long _position;
private bool _endReached;
@@ -54,38 +53,14 @@ public partial class LzmaStream : Stream, IStreamStack
private bool _needDictReset = true;
private bool _needProps = true;
private readonly Encoder _encoder;
private readonly Encoder? _encoder;
private bool _isDisposed;
public LzmaStream(byte[] properties, Stream inputStream, bool leaveOpen = false)
: this(properties, inputStream, -1, -1, null, properties.Length < 5, leaveOpen) { }
public LzmaStream(byte[] properties, Stream inputStream, long inputSize, bool leaveOpen = false)
: this(properties, inputStream, inputSize, -1, null, properties.Length < 5, leaveOpen) { }
public LzmaStream(
private LzmaStream(
byte[] properties,
Stream inputStream,
long inputSize,
long outputSize,
bool leaveOpen = false
)
: this(
properties,
inputStream,
inputSize,
outputSize,
null,
properties.Length < 5,
leaveOpen
) { }
public LzmaStream(
byte[] properties,
Stream inputStream,
long inputSize,
long outputSize,
Stream presetDictionary,
bool isLzma2,
bool leaveOpen = false
)
@@ -95,21 +70,10 @@ public partial class LzmaStream : Stream, IStreamStack
_outputSize = outputSize;
_isLzma2 = isLzma2;
_leaveOpen = leaveOpen;
#if DEBUG_STREAMS
this.DebugConstruct(typeof(LzmaStream));
#endif
if (!isLzma2)
{
_dictionarySize = BinaryPrimitives.ReadInt32LittleEndian(properties.AsSpan(1));
_outWindow.Create(_dictionarySize);
if (presetDictionary != null)
{
_outWindow.Train(presetDictionary);
}
_rangeDecoder.Init(inputStream);
_decoder = new Decoder();
_decoder.SetDecoderProperties(properties);
@@ -124,25 +88,72 @@ public partial class LzmaStream : Stream, IStreamStack
_dictionarySize <<= (properties[0] >> 1) + 11;
_outWindow.Create(_dictionarySize);
if (presetDictionary != null)
{
_outWindow.Train(presetDictionary);
_needDictReset = false;
}
Properties = new byte[1];
_availableBytes = 0;
}
}
public LzmaStream(LzmaEncoderProperties properties, bool isLzma2, Stream outputStream)
: this(properties, isLzma2, null, outputStream) { }
public LzmaStream(
public static LzmaStream Create(byte[] properties, Stream inputStream, bool leaveOpen = false)
=> Create(properties, inputStream, -1, -1, null, properties.Length < 5, leaveOpen);
public static LzmaStream Create(byte[] properties, Stream inputStream, long inputSize, bool leaveOpen = false)
=> Create(properties, inputStream, inputSize, -1, null, properties.Length < 5, leaveOpen);
public static LzmaStream Create(
byte[] properties,
Stream inputStream,
long inputSize,
long outputSize,
bool leaveOpen = false
)
=> Create(
properties,
inputStream,
inputSize,
outputSize,
null,
properties.Length < 5,
leaveOpen
);
public static LzmaStream Create(
byte[] properties,
Stream inputStream,
long inputSize,
long outputSize,
Stream? presetDictionary,
bool isLzma2,
bool leaveOpen = false
)
{
var lzma = new LzmaStream(properties, inputStream, inputSize, outputSize, isLzma2, leaveOpen);
if (!isLzma2)
{
if (presetDictionary != null)
{
lzma._outWindow.Train(presetDictionary);
}
lzma._rangeDecoder.Init(inputStream);
}
else
{
if (presetDictionary != null)
{
lzma. _outWindow.Train(presetDictionary);
lzma. _needDictReset = false;
}
}
return lzma;
}
private LzmaStream(
LzmaEncoderProperties properties,
bool isLzma2,
Stream presetDictionary,
Stream outputStream
Stream? presetDictionary
)
{
_isLzma2 = isLzma2;
@@ -160,17 +171,32 @@ public partial class LzmaStream : Stream, IStreamStack
_encoder.WriteCoderProperties(prop);
Properties = prop;
_encoder.SetStreams(null, outputStream, -1, -1);
#if DEBUG_STREAMS
this.DebugConstruct(typeof(LzmaStream));
#endif
if (presetDictionary != null)
{
_encoder.Train(presetDictionary);
}
}
public static LzmaStream Create(LzmaEncoderProperties properties, bool isLzma2, Stream outputStream)
=> Create(properties, isLzma2, null, outputStream);
public static LzmaStream Create(
LzmaEncoderProperties properties,
bool isLzma2,
Stream? presetDictionary,
Stream outputStream
)
{
var lzma = new LzmaStream(properties, isLzma2, presetDictionary);
lzma._encoder!.SetStreams(null, outputStream, -1, -1);
if (presetDictionary != null)
{
lzma._encoder.Train(presetDictionary);
}
return lzma;
}
public override bool CanRead => _encoder == null;
@@ -250,7 +276,7 @@ public partial class LzmaStream : Stream, IStreamStack
{
_inputPosition += _outWindow.CopyStream(_inputStream, toProcess);
}
else if (_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0)
else if (_decoder!.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0)
{
_availableBytes = _outWindow.AvailableBytes;
}
@@ -271,7 +297,7 @@ public partial class LzmaStream : Stream, IStreamStack
{
// Stream might have End Of Stream marker
_outWindow.SetLimit(toProcess + 1);
if (!_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder))
if (!_decoder!.Code(_dictionarySize, _outWindow, _rangeDecoder))
{
_rangeDecoder.ReleaseStream();
throw new DataErrorException();
@@ -341,7 +367,7 @@ public partial class LzmaStream : Stream, IStreamStack
{
_inputPosition += _outWindow.CopyStream(_inputStream, 1);
}
else if (_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0)
else if (_decoder!.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0)
{
_availableBytes = _outWindow.AvailableBytes;
}
@@ -360,7 +386,7 @@ public partial class LzmaStream : Stream, IStreamStack
{
// Stream might have End Of Stream marker
_outWindow.SetLimit(2);
if (!_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder))
if (!_decoder!.Code(_dictionarySize, _outWindow, _rangeDecoder))
{
_rangeDecoder.ReleaseStream();
throw new DataErrorException();
@@ -381,7 +407,7 @@ public partial class LzmaStream : Stream, IStreamStack
private void DecodeChunkHeader()
{
var control = _inputStream.ReadByte();
var control = _inputStream!.ReadByte();
_inputPosition++;
if (control == 0x00)

View File

@@ -51,7 +51,7 @@ internal static class DecoderRegistry
return new DeltaFilter(false, inStreams.Single(), info);
case K_LZMA:
case K_LZMA2:
return new LzmaStream(info, inStreams.Single(), -1, limit);
return LzmaStream.Create(info, inStreams.Single(), -1, limit);
case CMethodId.K_AES_ID:
return new AesDecoderStream(inStreams.Single(), info, pass, limit);
case K_BCJ:

View File

@@ -50,7 +50,7 @@ public class Lzma2Filter : BlockFilter
public override void ValidateFilter() { }
public override void SetBaseStream(Stream stream) =>
BaseStream = new LzmaStream(new[] { _dictionarySize }, stream);
BaseStream = LzmaStream.Create(new[] { _dictionarySize }, stream);
public override int Read(byte[] buffer, int offset, int count) =>
BaseStream.Read(buffer, offset, count);

View File

@@ -443,7 +443,7 @@ public partial class ZipWriter : AbstractWriter
counting.WriteByte(5);
counting.WriteByte(0);
var lzmaStream = new LzmaStream(
var lzmaStream = LzmaStream.Create(
new LzmaEncoderProperties(!originalStream.CanSeek),
false,
counting

View File

@@ -147,7 +147,7 @@ public class DisposalTests
// 5 bytes: 1 byte properties + 4 bytes dictionary size (little endian)
// Dictionary size = 1024 (0x400) -> 00 04 00 00
var lzmaProps = new byte[] { 0, 0, 4, 0, 0 };
VerifyAlwaysDispose(stream => new LzmaStream(lzmaProps, stream));
VerifyAlwaysDispose(stream => LzmaStream.Create(lzmaProps, stream));
}
[Fact]

View File

@@ -16,7 +16,7 @@ public class LzmaStreamAsyncTests
var compressedData = new byte[] { 0x01, 0x00, 0x00, 0x58, 0x00 };
var lzma2Stream = new MemoryStream(compressedData);
var decompressor = new LzmaStream(properties, lzma2Stream, 5, 1);
var decompressor = LzmaStream.Create(properties, lzma2Stream, 5, 1);
var buffer = new byte[1];
var bytesRead = await decompressor.ReadAsync(buffer, 0, 1).ConfigureAwait(false);
Assert.Equal(1, bytesRead);
@@ -540,7 +540,7 @@ public class LzmaStreamAsyncTests
{
using var inputStream = new MemoryStream(LzmaResultData);
using MemoryStream outputStream = new();
using var lzmaStream = new LzmaStream(LzmaEncoderProperties.Default, false, outputStream);
using var lzmaStream = LzmaStream.Create(LzmaEncoderProperties.Default, false, outputStream);
await inputStream.CopyToAsync(lzmaStream).ConfigureAwait(false);
lzmaStream.Close();
Assert.NotEqual(0, outputStream.Length);
@@ -551,7 +551,7 @@ public class LzmaStreamAsyncTests
{
var input = new MemoryStream(LzmaResultData);
var compressed = new MemoryStream();
var lzmaEncodingStream = new LzmaStream(LzmaEncoderProperties.Default, false, compressed);
var lzmaEncodingStream = LzmaStream.Create(LzmaEncoderProperties.Default, false, compressed);
await input.CopyToAsync(lzmaEncodingStream).ConfigureAwait(false);
lzmaEncodingStream.Close();
compressed.Position = 0;
@@ -577,7 +577,7 @@ public class LzmaStreamAsyncTests
long decompressedSize
)
{
var lzmaStream = new LzmaStream(
var lzmaStream = LzmaStream.Create(
properties,
compressedStream,
compressedSize,

View File

@@ -15,7 +15,7 @@ public class LzmaStreamTests
var compressedData = new byte[] { 0x01, 0x00, 0x00, 0x58, 0x00 };
var lzma2Stream = new MemoryStream(compressedData);
var decompressor = new LzmaStream(properties, lzma2Stream, 5, 1);
var decompressor = LzmaStream.Create(properties, lzma2Stream, 5, 1);
Assert.Equal('X', decompressor.ReadByte());
}
@@ -536,7 +536,7 @@ public class LzmaStreamTests
{
using var inputStream = new MemoryStream(LzmaResultData);
using MemoryStream outputStream = new();
using var lzmaStream = new LzmaStream(LzmaEncoderProperties.Default, false, outputStream);
using var lzmaStream = LzmaStream.Create(LzmaEncoderProperties.Default, false, outputStream);
inputStream.CopyTo(lzmaStream);
lzmaStream.Close();
Assert.NotEqual(0, outputStream.Length);
@@ -547,7 +547,7 @@ public class LzmaStreamTests
{
var input = new MemoryStream(LzmaResultData);
var compressed = new MemoryStream();
var lzmaEncodingStream = new LzmaStream(LzmaEncoderProperties.Default, false, compressed);
var lzmaEncodingStream = LzmaStream.Create(LzmaEncoderProperties.Default, false, compressed);
input.CopyTo(lzmaEncodingStream);
lzmaEncodingStream.Close();
compressed.Position = 0;
@@ -572,7 +572,7 @@ public class LzmaStreamTests
long decompressedSize
)
{
var lzmaStream = new LzmaStream(
var lzmaStream = LzmaStream.Create(
properties,
compressedStream,
compressedSize,