mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-11-15 17:02:03 +00:00
Tar and Xz mostly work
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Compressors.BZip2
|
||||
{
|
||||
@@ -65,12 +68,17 @@ namespace SharpCompress.Compressors.BZip2
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return stream.Read(buffer, offset, count);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return stream.ReadAsync(buffer, cancellationToken);
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
return stream.ReadByte();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
@@ -83,28 +91,19 @@ namespace SharpCompress.Compressors.BZip2
|
||||
stream.SetLength(value);
|
||||
}
|
||||
|
||||
#if !NET461 && !NETSTANDARD2_0
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
return stream.Read(buffer);
|
||||
return stream.WriteAsync(buffer, cancellationToken);
|
||||
}
|
||||
|
||||
public override void Write(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
stream.Write(buffer);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
stream.Write(buffer, offset, count);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
stream.WriteByte(value);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -112,11 +111,12 @@ namespace SharpCompress.Compressors.BZip2
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsBZip2(Stream stream)
|
||||
public static async ValueTask<bool> IsBZip2Async(Stream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
BinaryReader br = new BinaryReader(stream);
|
||||
byte[] chars = br.ReadBytes(2);
|
||||
if (chars.Length < 2 || chars[0] != 'B' || chars[1] != 'Z')
|
||||
using var rented = MemoryPool<byte>.Shared.Rent(2);
|
||||
var chars = rented.Memory.Slice(0, 2);
|
||||
await stream.ReadAsync(chars, cancellationToken);
|
||||
if (chars.Length < 2 || chars.Span[0] != 'B' || chars.Span[1] != 'Z')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Compressors.Xz
|
||||
{
|
||||
@@ -15,20 +18,20 @@ namespace SharpCompress.Compressors.Xz
|
||||
{
|
||||
return unchecked((uint)ReadLittleEndianInt32(reader));
|
||||
}
|
||||
public static int ReadLittleEndianInt32(this Stream stream)
|
||||
public static async ValueTask<int> ReadLittleEndianInt32(this Stream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
byte[] bytes = new byte[4];
|
||||
var read = stream.ReadFully(bytes);
|
||||
if (!read)
|
||||
using var buffer = MemoryPool<byte>.Shared.Rent(4);
|
||||
var read = await stream.ReadAsync(buffer.Memory.Slice(0, 4), cancellationToken);
|
||||
if (read != 4)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
return (bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24));
|
||||
return (buffer.Memory.Span[0] + (buffer.Memory.Span[1] << 8) + (buffer.Memory.Span[2] << 16) + (buffer.Memory.Span[3] << 24));
|
||||
}
|
||||
|
||||
internal static uint ReadLittleEndianUInt32(this Stream stream)
|
||||
internal static async ValueTask<uint> ReadLittleEndianUInt32(this Stream stream, CancellationToken cancellationToken)
|
||||
{
|
||||
return unchecked((uint)ReadLittleEndianInt32(stream));
|
||||
return unchecked((uint)await ReadLittleEndianInt32(stream, cancellationToken));
|
||||
}
|
||||
|
||||
internal static byte[] ToBigEndianBytes(this uint uint32)
|
||||
|
||||
@@ -12,17 +12,17 @@ namespace SharpCompress.Compressors.Xz
|
||||
|
||||
private static UInt32[] defaultTable;
|
||||
|
||||
public static UInt32 Compute(byte[] buffer)
|
||||
public static UInt32 Compute(ReadOnlyMemory<byte> buffer)
|
||||
{
|
||||
return Compute(DefaultSeed, buffer);
|
||||
}
|
||||
|
||||
public static UInt32 Compute(UInt32 seed, byte[] buffer)
|
||||
public static UInt32 Compute(UInt32 seed, ReadOnlyMemory<byte> buffer)
|
||||
{
|
||||
return Compute(DefaultPolynomial, seed, buffer);
|
||||
}
|
||||
|
||||
public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer)
|
||||
public static UInt32 Compute(UInt32 polynomial, UInt32 seed, ReadOnlyMemory<byte> buffer)
|
||||
{
|
||||
return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length);
|
||||
}
|
||||
@@ -61,12 +61,12 @@ namespace SharpCompress.Compressors.Xz
|
||||
return createTable;
|
||||
}
|
||||
|
||||
private static UInt32 CalculateHash(UInt32[] table, UInt32 seed, IList<byte> buffer, int start, int size)
|
||||
private static UInt32 CalculateHash(UInt32[] table, UInt32 seed, ReadOnlyMemory<byte> buffer, int start, int size)
|
||||
{
|
||||
var crc = seed;
|
||||
for (var i = start; i < size - start; i++)
|
||||
{
|
||||
crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff];
|
||||
crc = (crc >> 8) ^ table[buffer.Span[i] ^ crc & 0xff];
|
||||
}
|
||||
|
||||
return crc;
|
||||
|
||||
@@ -23,6 +23,11 @@ namespace SharpCompress.Compressors.Xz
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.Xz.Filters;
|
||||
|
||||
namespace SharpCompress.Compressors.Xz
|
||||
@@ -19,7 +21,7 @@ namespace SharpCompress.Compressors.Xz
|
||||
private bool _streamConnected;
|
||||
private int _numFilters;
|
||||
private byte _blockHeaderSizeByte;
|
||||
private Stream _decomStream;
|
||||
private Stream? _decomStream;
|
||||
private bool _endOfStream;
|
||||
private bool _paddingSkipped;
|
||||
private bool _crcChecked;
|
||||
@@ -32,12 +34,12 @@ namespace SharpCompress.Compressors.Xz
|
||||
_checkSize = checkSize;
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int bytesRead = 0;
|
||||
if (!HeaderIsLoaded)
|
||||
{
|
||||
LoadHeader();
|
||||
await LoadHeader(cancellationToken);
|
||||
}
|
||||
|
||||
if (!_streamConnected)
|
||||
@@ -45,12 +47,12 @@ namespace SharpCompress.Compressors.Xz
|
||||
ConnectStream();
|
||||
}
|
||||
|
||||
if (!_endOfStream)
|
||||
if (!_endOfStream && _decomStream is not null)
|
||||
{
|
||||
bytesRead = _decomStream.Read(buffer, offset, count);
|
||||
bytesRead = await _decomStream.ReadAsync(buffer, cancellationToken);
|
||||
}
|
||||
|
||||
if (bytesRead != count)
|
||||
if (bytesRead != buffer.Length)
|
||||
{
|
||||
_endOfStream = true;
|
||||
}
|
||||
@@ -105,12 +107,15 @@ namespace SharpCompress.Compressors.Xz
|
||||
_streamConnected = true;
|
||||
}
|
||||
|
||||
private void LoadHeader()
|
||||
private async ValueTask LoadHeader(CancellationToken cancellationToken)
|
||||
{
|
||||
ReadHeaderSize();
|
||||
byte[] headerCache = CacheHeader();
|
||||
await ReadHeaderSize(cancellationToken);
|
||||
using var blockHeaderWithoutCrc = MemoryPool<byte>.Shared.Rent(BlockHeaderSize - 4);
|
||||
var headerCache = blockHeaderWithoutCrc.Memory.Slice(0, BlockHeaderSize - 4);
|
||||
await CacheHeader(headerCache, cancellationToken);
|
||||
|
||||
using (var cache = new MemoryStream(headerCache))
|
||||
//TODO: memory-size this
|
||||
await using (var cache = new MemoryStream(headerCache.ToArray()))
|
||||
using (var cachedReader = new BinaryReader(cache))
|
||||
{
|
||||
cachedReader.BaseStream.Position = 1; // skip the header size byte
|
||||
@@ -120,33 +125,32 @@ namespace SharpCompress.Compressors.Xz
|
||||
HeaderIsLoaded = true;
|
||||
}
|
||||
|
||||
private void ReadHeaderSize()
|
||||
private async ValueTask ReadHeaderSize(CancellationToken cancellationToken)
|
||||
{
|
||||
_blockHeaderSizeByte = (byte)BaseStream.ReadByte();
|
||||
using var buffer = MemoryPool<byte>.Shared.Rent(1);
|
||||
await BaseStream.ReadAsync(buffer.Memory.Slice(0, 1), cancellationToken);
|
||||
_blockHeaderSizeByte = buffer.Memory.Span[0];
|
||||
if (_blockHeaderSizeByte == 0)
|
||||
{
|
||||
throw new XZIndexMarkerReachedException();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] CacheHeader()
|
||||
private async ValueTask CacheHeader(Memory<byte> blockHeaderWithoutCrc, CancellationToken cancellationToken)
|
||||
{
|
||||
byte[] blockHeaderWithoutCrc = new byte[BlockHeaderSize - 4];
|
||||
blockHeaderWithoutCrc[0] = _blockHeaderSizeByte;
|
||||
var read = BaseStream.Read(blockHeaderWithoutCrc, 1, BlockHeaderSize - 5);
|
||||
blockHeaderWithoutCrc.Span[0] = _blockHeaderSizeByte;
|
||||
var read = await BaseStream.ReadAsync(blockHeaderWithoutCrc.Slice( 1, BlockHeaderSize - 5), cancellationToken);
|
||||
if (read != BlockHeaderSize - 5)
|
||||
{
|
||||
throw new EndOfStreamException("Reached end of stream unexectedly");
|
||||
}
|
||||
|
||||
uint crc = BaseStream.ReadLittleEndianUInt32();
|
||||
uint crc = await BaseStream.ReadLittleEndianUInt32(cancellationToken);
|
||||
uint calcCrc = Crc32.Compute(blockHeaderWithoutCrc);
|
||||
if (crc != calcCrc)
|
||||
{
|
||||
throw new InvalidDataException("Block header corrupt");
|
||||
}
|
||||
|
||||
return blockHeaderWithoutCrc;
|
||||
}
|
||||
|
||||
private void ReadBlockFlags(BinaryReader reader)
|
||||
|
||||
@@ -1,58 +1,65 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Compressors.Xz
|
||||
{
|
||||
public class XZHeader
|
||||
{
|
||||
private readonly BinaryReader _reader;
|
||||
private readonly byte[] MagicHeader = { 0xFD, 0x37, 0x7A, 0x58, 0x5a, 0x00 };
|
||||
private readonly Stream _stream;
|
||||
private static readonly ReadOnlyMemory<byte> MagicHeader = new(new byte[]{ 0xFD, 0x37, 0x7A, 0x58, 0x5a, 0x00 });
|
||||
|
||||
public CheckType BlockCheckType { get; private set; }
|
||||
public int BlockCheckSize => ((((int)BlockCheckType) + 2) / 3) * 4;
|
||||
|
||||
public XZHeader(BinaryReader reader)
|
||||
public XZHeader(Stream reader)
|
||||
{
|
||||
_reader = reader;
|
||||
_stream = reader;
|
||||
}
|
||||
|
||||
public static XZHeader FromStream(Stream stream)
|
||||
public static async ValueTask<XZHeader> FromStream(Stream stream, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var header = new XZHeader(new BinaryReader(new NonDisposingStream(stream), Encoding.UTF8));
|
||||
header.Process();
|
||||
var header = new XZHeader(new NonDisposingStream(stream));
|
||||
await header.Process(cancellationToken);
|
||||
return header;
|
||||
}
|
||||
|
||||
public void Process()
|
||||
public async ValueTask Process(CancellationToken cancellationToken = default)
|
||||
{
|
||||
CheckMagicBytes(_reader.ReadBytes(6));
|
||||
ProcessStreamFlags();
|
||||
using var header = MemoryPool<byte>.Shared.Rent(6);
|
||||
await _stream.ReadAsync(header.Memory.Slice(0, 6), cancellationToken);
|
||||
CheckMagicBytes(header.Memory.Slice(0, 6));
|
||||
await ProcessStreamFlags(cancellationToken);
|
||||
}
|
||||
|
||||
private void ProcessStreamFlags()
|
||||
private async ValueTask ProcessStreamFlags(CancellationToken cancellationToken)
|
||||
{
|
||||
byte[] streamFlags = _reader.ReadBytes(2);
|
||||
UInt32 crc = _reader.ReadLittleEndianUInt32();
|
||||
UInt32 calcCrc = Crc32.Compute(streamFlags);
|
||||
using var header = MemoryPool<byte>.Shared.Rent(6);
|
||||
await _stream.ReadAsync(header.Memory.Slice(0, 2), cancellationToken);
|
||||
|
||||
BlockCheckType = (CheckType)(header.Memory.Span[1] & 0x0F);
|
||||
byte futureUse = (byte)(header.Memory.Span[1] & 0xF0);
|
||||
if (futureUse != 0 || header.Memory.Span[0] != 0)
|
||||
{
|
||||
throw new InvalidDataException("Unknown XZ Stream Version");
|
||||
}
|
||||
|
||||
UInt32 crc = await _stream.ReadLittleEndianUInt32(cancellationToken);
|
||||
UInt32 calcCrc = Crc32.Compute(header.Memory.Slice(0, 2));
|
||||
if (crc != calcCrc)
|
||||
{
|
||||
throw new InvalidDataException("Stream header corrupt");
|
||||
}
|
||||
|
||||
BlockCheckType = (CheckType)(streamFlags[1] & 0x0F);
|
||||
byte futureUse = (byte)(streamFlags[1] & 0xF0);
|
||||
if (futureUse != 0 || streamFlags[0] != 0)
|
||||
{
|
||||
throw new InvalidDataException("Unknown XZ Stream Version");
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckMagicBytes(byte[] header)
|
||||
private void CheckMagicBytes(ReadOnlyMemory<byte> header)
|
||||
{
|
||||
if (!header.SequenceEqual(MagicHeader))
|
||||
if (!header.Equals(MagicHeader))
|
||||
{
|
||||
throw new InvalidDataException("Invalid XZ Stream");
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Compressors.Xz
|
||||
{
|
||||
[CLSCompliant(false)]
|
||||
public sealed class XZStream : XZReadOnlyStream
|
||||
{
|
||||
public static bool IsXZStream(Stream stream)
|
||||
public static async ValueTask<bool> IsXZStreamAsync(Stream stream, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
return null != XZHeader.FromStream(stream);
|
||||
return null != await XZHeader.FromStream(stream, cancellationToken);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -22,7 +22,7 @@ namespace SharpCompress.Compressors.Xz
|
||||
|
||||
private void AssertBlockCheckTypeIsSupported()
|
||||
{
|
||||
switch (Header.BlockCheckType)
|
||||
switch (Header?.BlockCheckType)
|
||||
{
|
||||
case CheckType.NONE:
|
||||
break;
|
||||
@@ -36,11 +36,11 @@ namespace SharpCompress.Compressors.Xz
|
||||
throw new NotSupportedException("Check Type unknown to this version of decoder.");
|
||||
}
|
||||
}
|
||||
public XZHeader Header { get; private set; }
|
||||
public XZIndex Index { get; private set; }
|
||||
public XZFooter Footer { get; private set; }
|
||||
public XZHeader? Header { get; private set; }
|
||||
public XZIndex? Index { get; private set; }
|
||||
public XZFooter? Footer { get; private set; }
|
||||
public bool HeaderIsRead { get; private set; }
|
||||
private XZBlock _currentBlock;
|
||||
private XZBlock? _currentBlock;
|
||||
|
||||
private bool _endOfStream;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace SharpCompress.Compressors.Xz
|
||||
{
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int bytesRead = 0;
|
||||
if (_endOfStream)
|
||||
@@ -58,11 +58,11 @@ namespace SharpCompress.Compressors.Xz
|
||||
|
||||
if (!HeaderIsRead)
|
||||
{
|
||||
ReadHeader();
|
||||
await ReadHeader();
|
||||
}
|
||||
|
||||
bytesRead = ReadBlocks(buffer, offset, count);
|
||||
if (bytesRead < count)
|
||||
bytesRead = await ReadBlocks(buffer, cancellationToken);
|
||||
if (bytesRead < buffer.Length)
|
||||
{
|
||||
_endOfStream = true;
|
||||
ReadIndex();
|
||||
@@ -71,9 +71,9 @@ namespace SharpCompress.Compressors.Xz
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
private void ReadHeader()
|
||||
private async ValueTask ReadHeader()
|
||||
{
|
||||
Header = XZHeader.FromStream(BaseStream);
|
||||
Header = await XZHeader.FromStream(BaseStream);
|
||||
AssertBlockCheckTypeIsSupported();
|
||||
HeaderIsRead = true;
|
||||
}
|
||||
@@ -90,29 +90,29 @@ namespace SharpCompress.Compressors.Xz
|
||||
// TODO verify footer
|
||||
}
|
||||
|
||||
private int ReadBlocks(byte[] buffer, int offset, int count)
|
||||
private async ValueTask<int> ReadBlocks(Memory<byte> buffer, CancellationToken cancellationToken)
|
||||
{
|
||||
int bytesRead = 0;
|
||||
if (_currentBlock is null)
|
||||
{
|
||||
NextBlock();
|
||||
_currentBlock = NextBlock();
|
||||
}
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
try
|
||||
{
|
||||
if (bytesRead >= count)
|
||||
if (bytesRead >= buffer.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
int remaining = count - bytesRead;
|
||||
int newOffset = offset + bytesRead;
|
||||
int justRead = _currentBlock.Read(buffer, newOffset, remaining);
|
||||
int remaining = buffer.Length - bytesRead;
|
||||
int newOffset = bytesRead;
|
||||
int justRead = await _currentBlock.ReadAsync(buffer.Slice(newOffset, remaining), cancellationToken);
|
||||
if (justRead < remaining)
|
||||
{
|
||||
NextBlock();
|
||||
_currentBlock = NextBlock();
|
||||
}
|
||||
|
||||
bytesRead += justRead;
|
||||
@@ -125,9 +125,9 @@ namespace SharpCompress.Compressors.Xz
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
private void NextBlock()
|
||||
private XZBlock NextBlock()
|
||||
{
|
||||
_currentBlock = new XZBlock(BaseStream, Header.BlockCheckType, Header.BlockCheckSize);
|
||||
return new XZBlock(BaseStream, Header!.BlockCheckType, Header!.BlockCheckSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Archives.GZip;
|
||||
//using SharpCompress.Archives.Rar;
|
||||
@@ -27,7 +28,7 @@ namespace SharpCompress.Readers
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static async ValueTask<IReader> OpenAsync(Stream stream, ReaderOptions? options = null)
|
||||
public static async ValueTask<IReader> OpenAsync(Stream stream, ReaderOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
options ??= new ReaderOptions()
|
||||
@@ -42,11 +43,11 @@ namespace SharpCompress.Readers
|
||||
return ZipReader.Open(rewindableStream, options);
|
||||
}
|
||||
rewindableStream.Rewind(false);
|
||||
if (await GZipArchive.IsGZipFileAsync(rewindableStream))
|
||||
if (await GZipArchive.IsGZipFileAsync(rewindableStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(false);
|
||||
GZipStream testStream = new GZipStream(rewindableStream, CompressionMode.Decompress);
|
||||
if (await TarArchive.IsTarFileAsync(testStream))
|
||||
GZipStream testStream = new(rewindableStream, CompressionMode.Decompress);
|
||||
if (await TarArchive.IsTarFileAsync(testStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return new TarReader(rewindableStream, options, CompressionType.GZip);
|
||||
@@ -56,11 +57,11 @@ namespace SharpCompress.Readers
|
||||
}
|
||||
|
||||
rewindableStream.Rewind(false);
|
||||
if (BZip2Stream.IsBZip2(rewindableStream))
|
||||
if (await BZip2Stream.IsBZip2Async(rewindableStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(false);
|
||||
BZip2Stream testStream = new BZip2Stream(new NonDisposingStream(rewindableStream), CompressionMode.Decompress, false);
|
||||
if (await TarArchive.IsTarFileAsync(testStream))
|
||||
BZip2Stream testStream = new(new NonDisposingStream(rewindableStream), CompressionMode.Decompress, false);
|
||||
if (await TarArchive.IsTarFileAsync(testStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return new TarReader(rewindableStream, options, CompressionType.BZip2);
|
||||
@@ -71,8 +72,8 @@ namespace SharpCompress.Readers
|
||||
if (LZipStream.IsLZipFile(rewindableStream))
|
||||
{
|
||||
rewindableStream.Rewind(false);
|
||||
LZipStream testStream = new LZipStream(new NonDisposingStream(rewindableStream), CompressionMode.Decompress);
|
||||
if (await TarArchive.IsTarFileAsync(testStream))
|
||||
LZipStream testStream = new(new NonDisposingStream(rewindableStream), CompressionMode.Decompress);
|
||||
if (await TarArchive.IsTarFileAsync(testStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return new TarReader(rewindableStream, options, CompressionType.LZip);
|
||||
@@ -86,17 +87,17 @@ namespace SharpCompress.Readers
|
||||
} */
|
||||
|
||||
rewindableStream.Rewind(false);
|
||||
if (await TarArchive.IsTarFileAsync(rewindableStream))
|
||||
if (await TarArchive.IsTarFileAsync(rewindableStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return await TarReader.OpenAsync(rewindableStream, options);
|
||||
return await TarReader.OpenAsync(rewindableStream, options, cancellationToken);
|
||||
}
|
||||
rewindableStream.Rewind(false);
|
||||
if (XZStream.IsXZStream(rewindableStream))
|
||||
if (await XZStream.IsXZStreamAsync(rewindableStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
XZStream testStream = new XZStream(rewindableStream);
|
||||
if (await TarArchive.IsTarFileAsync(testStream))
|
||||
XZStream testStream = new(rewindableStream);
|
||||
if (await TarArchive.IsTarFileAsync(testStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return new TarReader(rewindableStream, options, CompressionType.Xz);
|
||||
|
||||
@@ -69,17 +69,17 @@ namespace SharpCompress.Readers.Tar
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static async ValueTask<TarReader> OpenAsync(Stream stream, ReaderOptions? options = null)
|
||||
public static async ValueTask<TarReader> OpenAsync(Stream stream, ReaderOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
options = options ?? new ReaderOptions();
|
||||
RewindableStream rewindableStream = new RewindableStream(stream);
|
||||
options ??= new ReaderOptions();
|
||||
RewindableStream rewindableStream = new(stream);
|
||||
rewindableStream.StartRecording();
|
||||
if (await GZipArchive.IsGZipFileAsync(rewindableStream))
|
||||
if (await GZipArchive.IsGZipFileAsync(rewindableStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(false);
|
||||
GZipStream testStream = new GZipStream(rewindableStream, CompressionMode.Decompress);
|
||||
if (await TarArchive.IsTarFileAsync(testStream))
|
||||
GZipStream testStream = new(rewindableStream, CompressionMode.Decompress);
|
||||
if (await TarArchive.IsTarFileAsync(testStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return new TarReader(rewindableStream, options, CompressionType.GZip);
|
||||
@@ -88,11 +88,11 @@ namespace SharpCompress.Readers.Tar
|
||||
}
|
||||
|
||||
rewindableStream.Rewind(false);
|
||||
if (BZip2Stream.IsBZip2(rewindableStream))
|
||||
if (await BZip2Stream.IsBZip2Async(rewindableStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(false);
|
||||
BZip2Stream testStream = new BZip2Stream(rewindableStream, CompressionMode.Decompress, false);
|
||||
if (await TarArchive.IsTarFileAsync(testStream))
|
||||
BZip2Stream testStream = new(rewindableStream, CompressionMode.Decompress, false);
|
||||
if (await TarArchive.IsTarFileAsync(testStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return new TarReader(rewindableStream, options, CompressionType.BZip2);
|
||||
@@ -104,8 +104,8 @@ namespace SharpCompress.Readers.Tar
|
||||
if (LZipStream.IsLZipFile(rewindableStream))
|
||||
{
|
||||
rewindableStream.Rewind(false);
|
||||
LZipStream testStream = new LZipStream(rewindableStream, CompressionMode.Decompress);
|
||||
if (await TarArchive.IsTarFileAsync(testStream))
|
||||
LZipStream testStream = new(rewindableStream, CompressionMode.Decompress);
|
||||
if (await TarArchive.IsTarFileAsync(testStream, cancellationToken))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return new TarReader(rewindableStream, options, CompressionType.LZip);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using SharpCompress.Compressors.Xz;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Xz
|
||||
@@ -7,35 +8,33 @@ namespace SharpCompress.Test.Xz
|
||||
public class XZHeaderTests : XZTestsBase
|
||||
{
|
||||
[Fact]
|
||||
public void ChecksMagicNumber()
|
||||
public async ValueTask ChecksMagicNumber()
|
||||
{
|
||||
var bytes = Compressed.Clone() as byte[];
|
||||
bytes[3]++;
|
||||
using (Stream badMagicNumberStream = new MemoryStream(bytes))
|
||||
await using (Stream badMagicNumberStream = new MemoryStream(bytes))
|
||||
{
|
||||
BinaryReader br = new BinaryReader(badMagicNumberStream);
|
||||
var header = new XZHeader(br);
|
||||
var ex = Assert.Throws<InvalidDataException>(() => { header.Process(); });
|
||||
var header = new XZHeader(badMagicNumberStream);
|
||||
var ex = await Assert.ThrowsAsync<InvalidDataException>(async () => { await header.Process(); });
|
||||
Assert.Equal("Invalid XZ Stream", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CorruptHeaderThrows()
|
||||
public async ValueTask CorruptHeaderThrows()
|
||||
{
|
||||
var bytes = Compressed.Clone() as byte[];
|
||||
bytes[8]++;
|
||||
using (Stream badCrcStream = new MemoryStream(bytes))
|
||||
{
|
||||
BinaryReader br = new BinaryReader(badCrcStream);
|
||||
var header = new XZHeader(br);
|
||||
var ex = Assert.Throws<InvalidDataException>(() => { header.Process(); });
|
||||
var header = new XZHeader(badCrcStream);
|
||||
var ex = await Assert.ThrowsAsync<InvalidDataException>(async () => { await header.Process(); });
|
||||
Assert.Equal("Stream header corrupt", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BadVersionIfCrcOkButStreamFlagUnknown()
|
||||
public async ValueTask BadVersionIfCrcOkButStreamFlagUnknown()
|
||||
{
|
||||
var bytes = Compressed.Clone() as byte[];
|
||||
byte[] streamFlags = { 0x00, 0xF4 };
|
||||
@@ -44,35 +43,32 @@ namespace SharpCompress.Test.Xz
|
||||
crc.CopyTo(bytes, 8);
|
||||
using (Stream badFlagStream = new MemoryStream(bytes))
|
||||
{
|
||||
BinaryReader br = new BinaryReader(badFlagStream);
|
||||
var header = new XZHeader(br);
|
||||
var ex = Assert.Throws<InvalidDataException>(() => { header.Process(); });
|
||||
var header = new XZHeader(badFlagStream);
|
||||
var ex = await Assert.ThrowsAsync<InvalidDataException>(async () => { await header.Process(); });
|
||||
Assert.Equal("Unknown XZ Stream Version", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessesBlockCheckType()
|
||||
public async ValueTask ProcessesBlockCheckType()
|
||||
{
|
||||
BinaryReader br = new BinaryReader(CompressedStream);
|
||||
var header = new XZHeader(br);
|
||||
header.Process();
|
||||
var header = new XZHeader(CompressedStream);
|
||||
await header.Process();
|
||||
Assert.Equal(CheckType.CRC64, header.BlockCheckType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanCalculateBlockCheckSize()
|
||||
public async ValueTask CanCalculateBlockCheckSize()
|
||||
{
|
||||
BinaryReader br = new BinaryReader(CompressedStream);
|
||||
var header = new XZHeader(br);
|
||||
header.Process();
|
||||
var header = new XZHeader(CompressedStream);
|
||||
await header.Process();
|
||||
Assert.Equal(8, header.BlockCheckSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessesStreamHeaderFromFactory()
|
||||
public async ValueTask ProcessesStreamHeaderFromFactory()
|
||||
{
|
||||
var header = XZHeader.FromStream(CompressedStream);
|
||||
var header = await XZHeader.FromStream(CompressedStream);
|
||||
Assert.Equal(CheckType.CRC64, header.BlockCheckType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using SharpCompress.Compressors.Xz;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Xz
|
||||
@@ -7,34 +8,34 @@ namespace SharpCompress.Test.Xz
|
||||
public class XZStreamTests : XZTestsBase
|
||||
{
|
||||
[Fact]
|
||||
public void CanReadEmptyStream()
|
||||
public async ValueTask CanReadEmptyStream()
|
||||
{
|
||||
XZStream xz = new XZStream(CompressedEmptyStream);
|
||||
using (var sr = new StreamReader(xz))
|
||||
{
|
||||
string uncompressed = sr.ReadToEnd();
|
||||
string uncompressed = await sr.ReadToEndAsync();
|
||||
Assert.Equal(OriginalEmpty, uncompressed);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanReadStream()
|
||||
public async ValueTask CanReadStream()
|
||||
{
|
||||
XZStream xz = new XZStream(CompressedStream);
|
||||
using (var sr = new StreamReader(xz))
|
||||
{
|
||||
string uncompressed = sr.ReadToEnd();
|
||||
string uncompressed = await sr.ReadToEndAsync();
|
||||
Assert.Equal(Original, uncompressed);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanReadIndexedStream()
|
||||
public async ValueTask CanReadIndexedStream()
|
||||
{
|
||||
XZStream xz = new XZStream(CompressedIndexedStream);
|
||||
using (var sr = new StreamReader(xz))
|
||||
{
|
||||
string uncompressed = sr.ReadToEnd();
|
||||
string uncompressed = await sr.ReadToEndAsync();
|
||||
Assert.Equal(OriginalIndexed, uncompressed);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user