mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-07-08 18:16:30 +00:00
Cleanup: use some arraypool buffers
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.Xz.Filters;
|
||||
|
||||
namespace SharpCompress.Compressors.Xz;
|
||||
|
||||
@@ -32,6 +30,7 @@ public sealed partial class XZBlock
|
||||
if (!_endOfStream)
|
||||
{
|
||||
bytesRead = await _decomStream
|
||||
.NotNull()
|
||||
.ReadAsync(buffer, offset, count, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
UpdateCheck(buffer, offset, bytesRead);
|
||||
@@ -60,13 +59,21 @@ public sealed partial class XZBlock
|
||||
var bytes = (BaseStream.Position - _startPosition) % 4;
|
||||
if (bytes > 0)
|
||||
{
|
||||
var paddingBytes = new byte[4 - bytes];
|
||||
await BaseStream
|
||||
.ReadAsync(paddingBytes, 0, paddingBytes.Length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (paddingBytes.Any(b => b != 0))
|
||||
var size = 4 - (int)bytes;
|
||||
var paddingBytes = ArrayPool<byte>.Shared.Rent(size);
|
||||
try
|
||||
{
|
||||
throw new InvalidFormatException("Padding bytes were non-null");
|
||||
await BaseStream
|
||||
.ReadExactAsync(paddingBytes, 0, size, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (paddingBytes.Any(b => b != 0))
|
||||
{
|
||||
throw new InvalidFormatException("Padding bytes were non-null");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(paddingBytes);
|
||||
}
|
||||
}
|
||||
_paddingSkipped = true;
|
||||
@@ -74,12 +81,19 @@ public sealed partial class XZBlock
|
||||
|
||||
private async ValueTask CheckCrcAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var crc = new byte[_checkSize];
|
||||
await BaseStream
|
||||
.ReadExactAsync(crc, 0, _checkSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
VerifyCheck(crc);
|
||||
_crcChecked = true;
|
||||
var crc = ArrayPool<byte>.Shared.Rent(_checkSize);
|
||||
try
|
||||
{
|
||||
await BaseStream
|
||||
.ReadExactAsync(crc, 0, _checkSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
VerifyCheck(crc);
|
||||
_crcChecked = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(crc);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask LoadHeaderAsync(CancellationToken cancellationToken = default)
|
||||
@@ -99,12 +113,19 @@ public sealed partial class XZBlock
|
||||
|
||||
private async ValueTask ReadHeaderSizeAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var buffer = new byte[1];
|
||||
await BaseStream.ReadAsync(buffer, 0, 1, cancellationToken).ConfigureAwait(false);
|
||||
_blockHeaderSizeByte = buffer[0];
|
||||
if (_blockHeaderSizeByte == 0)
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(1);
|
||||
try
|
||||
{
|
||||
throw new XZIndexMarkerReachedException();
|
||||
await BaseStream.ReadExactAsync(buffer, 0, 1, cancellationToken).ConfigureAwait(false);
|
||||
_blockHeaderSizeByte = buffer[0];
|
||||
if (_blockHeaderSizeByte == 0)
|
||||
{
|
||||
throw new XZIndexMarkerReachedException();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.Xz.Filters;
|
||||
|
||||
@@ -16,20 +13,20 @@ namespace SharpCompress.Compressors.Xz;
|
||||
[CLSCompliant(false)]
|
||||
public sealed partial class XZBlock : XZReadOnlyStream
|
||||
{
|
||||
public int BlockHeaderSize => (_blockHeaderSizeByte + 1) * 4;
|
||||
private int BlockHeaderSize => (_blockHeaderSizeByte + 1) * 4;
|
||||
public ulong? CompressedSize { get; private set; }
|
||||
public ulong? UncompressedSize { get; private set; }
|
||||
public Stack<BlockFilter> Filters { get; private set; } = new();
|
||||
public bool HeaderIsLoaded { get; private set; }
|
||||
private readonly Stack<BlockFilter> _filters = new();
|
||||
private bool HeaderIsLoaded { get; set; }
|
||||
private readonly CheckType _checkType;
|
||||
private readonly int _checkSize;
|
||||
private uint _crc32 = Crc32.DefaultSeed;
|
||||
private ulong _crc64 = Crc64.DefaultSeed;
|
||||
private readonly SHA256 _sha256;
|
||||
private readonly SHA256? _sha256;
|
||||
private bool _streamConnected;
|
||||
private int _numFilters;
|
||||
private byte _blockHeaderSizeByte;
|
||||
private Stream _decomStream;
|
||||
private Stream? _decomStream;
|
||||
private bool _endOfStream;
|
||||
private bool _paddingSkipped;
|
||||
private bool _crcChecked;
|
||||
@@ -62,7 +59,7 @@ public sealed partial class XZBlock : XZReadOnlyStream
|
||||
|
||||
if (!_endOfStream)
|
||||
{
|
||||
bytesRead = _decomStream.Read(buffer, offset, count);
|
||||
bytesRead = _decomStream.NotNull().Read(buffer, offset, count);
|
||||
UpdateCheck(buffer, offset, bytesRead);
|
||||
}
|
||||
|
||||
@@ -125,54 +122,80 @@ public sealed partial class XZBlock : XZReadOnlyStream
|
||||
_crc64 = Crc64.CalculateHash(_crc64, Crc64.Table, bytes);
|
||||
break;
|
||||
case CheckType.SHA256:
|
||||
_sha256.TransformBlock(buffer, offset, count, null, 0);
|
||||
_sha256.NotNull().TransformBlock(buffer, offset, count, null, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void VerifyCheck(byte[] expected)
|
||||
{
|
||||
var actual = _checkType switch
|
||||
switch (_checkType)
|
||||
{
|
||||
CheckType.NONE => Array.Empty<byte>(),
|
||||
CheckType.CRC32 => GetLittleEndianBytes(~_crc32),
|
||||
CheckType.CRC64 => GetLittleEndianBytes(_crc64),
|
||||
CheckType.SHA256 => FinalizeSha256Check(),
|
||||
_ => throw new InvalidFormatException("Unsupported XZ check type"),
|
||||
};
|
||||
case CheckType.NONE:
|
||||
break;
|
||||
case CheckType.CRC32:
|
||||
GetLittleEndianBytes(~_crc32, expected);
|
||||
break;
|
||||
case CheckType.CRC64:
|
||||
GetLittleEndianBytes(~_crc64, expected);
|
||||
break;
|
||||
case CheckType.SHA256:
|
||||
FinalizeSha256Check(expected);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidFormatException("Unsupported XZ check type");
|
||||
}
|
||||
}
|
||||
|
||||
if (!expected.SequenceEqual(actual))
|
||||
private static void GetLittleEndianBytes(uint value, byte[] expected)
|
||||
{
|
||||
var bytes = ArrayPool<byte>.Shared.Rent(sizeof(uint));
|
||||
try
|
||||
{
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(bytes, value);
|
||||
if (!expected.SequenceEqual(bytes.AsSpan().Slice(0, sizeof(uint))))
|
||||
{
|
||||
throw new InvalidFormatException("Block check corrupt");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetLittleEndianBytes(ulong value, byte[] expected)
|
||||
{
|
||||
var bytes = ArrayPool<byte>.Shared.Rent(sizeof(ulong));
|
||||
try
|
||||
{
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(bytes, value);
|
||||
if (!expected.SequenceEqual(bytes.AsSpan().Slice(0, sizeof(ulong))))
|
||||
{
|
||||
throw new InvalidFormatException("Block check corrupt");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
private void FinalizeSha256Check(byte[] expected)
|
||||
{
|
||||
_sha256.NotNull().TransformFinalBlock(Array.Empty<byte>(), 0, 0);
|
||||
if (!expected.SequenceEqual(_sha256.NotNull().Hash))
|
||||
{
|
||||
throw new InvalidFormatException("Block check corrupt");
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] GetLittleEndianBytes(uint value)
|
||||
{
|
||||
var bytes = new byte[sizeof(uint)];
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(bytes, value);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private static byte[] GetLittleEndianBytes(ulong value)
|
||||
{
|
||||
var bytes = new byte[sizeof(ulong)];
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(bytes, value);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private byte[] FinalizeSha256Check()
|
||||
{
|
||||
_sha256.TransformFinalBlock(Array.Empty<byte>(), 0, 0);
|
||||
return _sha256.Hash;
|
||||
}
|
||||
|
||||
private void ConnectStream()
|
||||
{
|
||||
_decomStream = BaseStream;
|
||||
while (Filters.Any())
|
||||
while (_filters.Any())
|
||||
{
|
||||
var filter = Filters.Pop();
|
||||
var filter = _filters.Pop();
|
||||
filter.SetBaseStream(_decomStream);
|
||||
_decomStream = filter;
|
||||
}
|
||||
@@ -270,7 +293,7 @@ public sealed partial class XZBlock : XZReadOnlyStream
|
||||
}
|
||||
|
||||
filter.ValidateFilter();
|
||||
Filters.Push(filter);
|
||||
_filters.Push(filter);
|
||||
}
|
||||
if (nonLastSizeChangers > 2)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user