Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<NoWarn>${NoWarn};IDE0051</NoWarn>
</PropertyGroup>
</Project>
6 changes: 4 additions & 2 deletions src/SharpCompress/Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ public static class Constants
/// by rewinding and re-reading the same data.
/// </para>
/// <para>
/// <b>Default:</b> 81920 bytes (81KB) - sufficient for typical format detection.
/// <b>Default:</b> 163840 bytes (160KB) - sized to cover ZStandard's worst-case
/// first block on a tar archive (~131KB including frame header overhead).
/// ZStandard blocks can be up to 128KB, exceeding the previous 81KB default.
/// </para>
/// <para>
/// <b>Typical usage:</b> 500-1000 bytes for most archives
Expand All @@ -39,7 +41,7 @@ public static class Constants
/// </list>
/// </para>
/// </remarks>
public static int RewindableBufferSize { get; set; } = 81920;
public static int RewindableBufferSize { get; set; } = 163840;

public static CultureInfo DefaultCultureInfo { get; set; } = CultureInfo.InvariantCulture;
}
47 changes: 13 additions & 34 deletions src/SharpCompress/Common/Zip/WinzipAesCryptoStream.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,55 +86,34 @@ public override async ValueTask<int> ReadAsync(
private void ReadTransformBlocks(Span<byte> buffer, int count)
{
var posn = 0;
var last = count;
var remaining = count;

while (posn < buffer.Length && posn < last)
while (posn < buffer.Length && remaining > 0)
{
var n = ReadTransformOneBlock(buffer, posn, last);
var n = ReadTransformOneBlock(buffer, posn, remaining);
posn += n;
remaining -= n;
}
}

private int ReadTransformOneBlock(Span<byte> buffer, int offset, int last)
private int ReadTransformOneBlock(Span<byte> buffer, int offset, int remaining)
{
if (_isFinalBlock)
if (_counterOutOffset == BLOCK_SIZE_IN_BYTES)
{
throw new ArchiveOperationException();
FillCounterOut();
}

var bytesRemaining = last - offset;
var bytesToRead =
(bytesRemaining > BLOCK_SIZE_IN_BYTES) ? BLOCK_SIZE_IN_BYTES : bytesRemaining;

// update the counter
System.Buffers.Binary.BinaryPrimitives.WriteInt32LittleEndian(_counter, _nonce++);

// Determine if this is the final block
if ((bytesToRead == bytesRemaining) && (_totalBytesLeftToRead == 0))
{
_counterOut = _transform.TransformFinalBlock(_counter, 0, BLOCK_SIZE_IN_BYTES);
_isFinalBlock = true;
}
else
{
_transform.TransformBlock(
_counter,
0, // offset
BLOCK_SIZE_IN_BYTES,
_counterOut,
0
); // offset
}

XorInPlace(buffer, offset, bytesToRead);
return bytesToRead;
var bytesToXor = Math.Min(BLOCK_SIZE_IN_BYTES - _counterOutOffset, remaining);
XorInPlace(buffer, offset, bytesToXor, _counterOutOffset);
_counterOutOffset += bytesToXor;
return bytesToXor;
}

private void XorInPlace(Span<byte> buffer, int offset, int count)
private void XorInPlace(Span<byte> buffer, int offset, int count, int counterOffset)
{
for (var i = 0; i < count; i++)
{
buffer[offset + i] = (byte)(_counterOut[i] ^ buffer[offset + i]);
buffer[offset + i] = (byte)(_counterOut[counterOffset + i] ^ buffer[offset + i]);
}
}
#endif
Expand Down
61 changes: 24 additions & 37 deletions src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal partial class WinzipAesCryptoStream : Stream
private readonly ICryptoTransform _transform;
private int _nonce = 1;
private byte[] _counterOut = new byte[BLOCK_SIZE_IN_BYTES];
private bool _isFinalBlock;
private int _counterOutOffset = BLOCK_SIZE_IN_BYTES;
private long _totalBytesLeftToRead;
private bool _isDisposed;

Expand Down Expand Up @@ -123,58 +123,45 @@ public override int Read(byte[] buffer, int offset, int count)
return read;
}

private int ReadTransformOneBlock(byte[] buffer, int offset, int last)
private void FillCounterOut()
{
if (_isFinalBlock)
{
throw new ArchiveOperationException();
}

var bytesRemaining = last - offset;
var bytesToRead =
(bytesRemaining > BLOCK_SIZE_IN_BYTES) ? BLOCK_SIZE_IN_BYTES : bytesRemaining;

// update the counter
BinaryPrimitives.WriteInt32LittleEndian(_counter, _nonce++);

// Determine if this is the final block
if ((bytesToRead == bytesRemaining) && (_totalBytesLeftToRead == 0))
{
_counterOut = _transform.TransformFinalBlock(_counter, 0, BLOCK_SIZE_IN_BYTES);
_isFinalBlock = true;
}
else
{
_transform.TransformBlock(
_counter,
0, // offset
BLOCK_SIZE_IN_BYTES,
_counterOut,
0
); // offset
}

XorInPlace(buffer, offset, bytesToRead);
return bytesToRead;
_transform.TransformBlock(
_counter,
0, // offset
BLOCK_SIZE_IN_BYTES,
_counterOut,
0
); // offset
_counterOutOffset = 0;
}

private void XorInPlace(byte[] buffer, int offset, int count)
private void XorInPlace(byte[] buffer, int offset, int count, int counterOffset)
{
for (var i = 0; i < count; i++)
{
buffer[offset + i] = (byte)(_counterOut[i] ^ buffer[offset + i]);
buffer[offset + i] = (byte)(_counterOut[counterOffset + i] ^ buffer[offset + i]);
}
}

private void ReadTransformBlocks(byte[] buffer, int offset, int count)
{
var posn = offset;
var last = count + offset;
var remaining = count;

while (posn < buffer.Length && posn < last)
while (posn < buffer.Length && remaining > 0)
{
var n = ReadTransformOneBlock(buffer, posn, last);
posn += n;
if (_counterOutOffset == BLOCK_SIZE_IN_BYTES)
{
FillCounterOut();
}

var bytesToXor = Math.Min(BLOCK_SIZE_IN_BYTES - _counterOutOffset, remaining);
XorInPlace(buffer, posn, bytesToXor, _counterOutOffset);
_counterOutOffset += bytesToXor;
posn += bytesToXor;
remaining -= bytesToXor;
}
}

Expand Down
6 changes: 2 additions & 4 deletions src/SharpCompress/Common/Zip/ZipFilePart.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,8 @@ protected async ValueTask<Stream> GetCryptoStreamAsync(
}

if (
(
Header.CompressedSize == 0
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
) || Header.IsZip64
Header.CompressedSize == 0
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
)
{
plainStream = SharpCompressStream.CreateNonDisposing(plainStream); //make sure AES doesn't close
Expand Down
6 changes: 2 additions & 4 deletions src/SharpCompress/Common/Zip/ZipFilePart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,8 @@ protected Stream GetCryptoStream(Stream plainStream)
}

if (
(
Header.CompressedSize == 0
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
) || Header.IsZip64
Header.CompressedSize == 0
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
)
{
plainStream = SharpCompressStream.CreateNonDisposing(plainStream); //make sure AES doesn't close
Expand Down
8 changes: 8 additions & 0 deletions src/SharpCompress/Compressors/ArcLzw/ArcLzwStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ public List<byte> Decompress(byte[] input, bool useCrunched)

if (useCrunched)
{
if (input.Length == 0)
{
throw new InvalidFormatException("ArcLzwStream: compressed data is empty");
}
if (input[0] != BITS)
{
throw new InvalidFormatException($"File packed with {input[0]}, expected {BITS}.");
Expand Down Expand Up @@ -129,6 +133,10 @@ public List<byte> Decompress(byte[] input, bool useCrunched)

while (code >= 256)
{
if (code >= suffix.Length)
{
throw new InvalidFormatException("ArcLzwStream: code out of range");
}
stack.Push(suffix[code]);
code = prefix[code];
}
Expand Down
68 changes: 64 additions & 4 deletions src/SharpCompress/Compressors/BZip2/CBZip2InputStream.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,21 @@ private async ValueTask RecvDecodingTablesAsync(CancellationToken cancellationTo

/* Now the selectors */
nGroups = await BsRAsync(3, cancellationToken).ConfigureAwait(false);
if (nGroups < 2 || nGroups > BZip2Constants.N_GROUPS)
{
throw new InvalidFormatException("BZip2: invalid number of Huffman trees");
}
nSelectors = await BsRAsync(15, cancellationToken).ConfigureAwait(false);
for (i = 0; i < nSelectors; i++)
{
j = 0;
while (await BsRAsync(1, cancellationToken).ConfigureAwait(false) == 1)
{
j++;
if (j >= nGroups)
{
throw new InvalidFormatException("BZip2: invalid selector MTF value");
}
}
if (i < BZip2Constants.MAX_SELECTORS)
{
Expand All @@ -266,6 +274,10 @@ private async ValueTask RecvDecodingTablesAsync(CancellationToken cancellationTo
for (i = 0; i < nSelectors; i++)
{
v = selectorMtf[i];
if (v >= nGroups)
{
throw new InvalidFormatException("BZip2: selector MTF value out of range");
}
tmp = pos[v];
while (v > 0)
{
Expand Down Expand Up @@ -374,6 +386,10 @@ cache misses.
while (zvec > limit[zt][zn])
{
zn++;
if (zn >= BZip2Constants.MAX_CODE_LEN)
{
throw new InvalidFormatException("BZip2: Huffman code too long");
}
{
{
while (bsLive < 1)
Expand Down Expand Up @@ -405,7 +421,14 @@ cache misses.
}
zvec = (zvec << 1) | zj;
}
nextSym = perm[zt][zvec - basev[zt][zn]];
{
int permIdx = zvec - basev[zt][zn];
if (permIdx < 0 || permIdx >= perm[zt].Length)
{
throw new InvalidFormatException("BZip2: invalid Huffman symbol");
}
nextSym = perm[zt][permIdx];
}
}

while (true)
Expand Down Expand Up @@ -448,6 +471,10 @@ cache misses.
while (zvec > limit[zt][zn])
{
zn++;
if (zn >= BZip2Constants.MAX_CODE_LEN)
{
throw new InvalidFormatException("BZip2: Huffman code too long");
}
{
{
while (bsLive < 1)
Expand Down Expand Up @@ -479,7 +506,14 @@ cache misses.
}
zvec = (zvec << 1) | zj;
}
nextSym = perm[zt][zvec - basev[zt][zn]];
{
int permIdx = zvec - basev[zt][zn];
if (permIdx < 0 || permIdx >= perm[zt].Length)
{
throw new InvalidFormatException("BZip2: invalid Huffman symbol");
}
nextSym = perm[zt][permIdx];
}
}
} while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB);

Expand Down Expand Up @@ -550,6 +584,10 @@ hence the unrolling.
while (zvec > limit[zt][zn])
{
zn++;
if (zn >= BZip2Constants.MAX_CODE_LEN)
{
throw new InvalidFormatException("BZip2: Huffman code too long");
}
{
{
while (bsLive < 1)
Expand Down Expand Up @@ -581,7 +619,14 @@ hence the unrolling.
}
zvec = (zvec << 1) | zj;
}
nextSym = perm[zt][zvec - basev[zt][zn]];
{
int permIdx = zvec - basev[zt][zn];
if (permIdx < 0 || permIdx >= perm[zt].Length)
{
throw new InvalidFormatException("BZip2: invalid Huffman symbol");
}
nextSym = perm[zt][permIdx];
}
}
}
}
Expand All @@ -605,10 +650,18 @@ private async ValueTask SetupBlockAsync(CancellationToken cancellationToken)
for (i = 0; i <= last; i++)
{
ch = ll8[i];
if (cftab[ch] < 0 || cftab[ch] >= tt.Length)
{
throw new InvalidFormatException("BZip2: block data out of bounds");
}
tt[cftab[ch]] = i;
cftab[ch]++;
}

if (origPtr < 0 || origPtr >= tt.Length)
{
throw new InvalidFormatException("BZip2: origPtr out of bounds");
}
tPos = tt[origPtr];

count = 0;
Expand Down Expand Up @@ -806,6 +859,10 @@ private async ValueTask<int> BsRAsync(int n, CancellationToken cancellationToken
int v;
while (bsLive < n)
{
if (bsStream is null)
{
CompressedStreamEOF();
}
int zzi;
int thech = '\0';
var b = ArrayPool<byte>.Shared.Rent(1);
Expand Down Expand Up @@ -858,7 +915,10 @@ public static async ValueTask<CBZip2InputStream> CreateAsync(
cbZip2InputStream.ll8 = null;
cbZip2InputStream.tt = null;
cbZip2InputStream.BsSetStream(zStream);
await cbZip2InputStream.InitializeAsync(true, cancellationToken).ConfigureAwait(false);
if (!await cbZip2InputStream.InitializeAsync(true, cancellationToken).ConfigureAwait(false))
{
throw new InvalidFormatException("Not a valid BZip2 stream");
}
await cbZip2InputStream.InitBlockAsync(cancellationToken).ConfigureAwait(false);
await cbZip2InputStream.SetupBlockAsync(cancellationToken).ConfigureAwait(false);
return cbZip2InputStream;
Expand Down
Loading
Loading