more basic LLM async and fixed CRC async
This commit is contained in:
parent
884f0b702e
commit
ecd9317ab3
9 changed files with 124 additions and 48 deletions
|
|
@ -210,7 +210,7 @@ public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IAsyncArchive
|
|||
|
||||
public async ValueTask<IAsyncReader> ExtractAllEntriesAsync()
|
||||
{
|
||||
if (!IsSolid && Type != ArchiveType.SevenZip)
|
||||
if (!await IsSolidAsync() && Type != ArchiveType.SevenZip)
|
||||
{
|
||||
throw new SharpCompressException(
|
||||
"ExtractAllEntries can only be used on solid archives or 7Zip archives (which require random access)."
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ public partial class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>, I
|
|||
public override bool IsSolid => Volumes.First().IsSolidArchive;
|
||||
|
||||
public override async ValueTask<bool> IsSolidAsync() =>
|
||||
(await VolumesAsync.CastAsync<RarVolume>().FirstAsync()).IsSolidArchive;
|
||||
await (await VolumesAsync.CastAsync<RarVolume>().FirstAsync()).IsSolidArchiveAsync();
|
||||
|
||||
public override bool IsEncrypted => Entries.First(x => !x.IsDirectory).IsEncrypted;
|
||||
|
||||
|
|
|
|||
|
|
@ -41,27 +41,25 @@ internal class AsyncMarkingBinaryReader
|
|||
{
|
||||
CurrentReadByteCount += count;
|
||||
var bytes = new byte[count];
|
||||
await _reader.ReadBytesAsync(bytes, 0, count, cancellationToken).ConfigureAwait(false);
|
||||
await _reader.ReadBytesAsync(bytes, 0, count, cancellationToken).ConfigureAwait(false);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public virtual async ValueTask<ushort> ReadUInt16Async(
|
||||
public async ValueTask<ushort> ReadUInt16Async(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
CurrentReadByteCount += 2;
|
||||
var bytes = new byte[2];
|
||||
await _reader.ReadBytesAsync(bytes, 0, 2, cancellationToken).ConfigureAwait(false);
|
||||
var bytes = await ReadBytesAsync( 2, cancellationToken).ConfigureAwait(false);
|
||||
return BinaryPrimitives.ReadUInt16LittleEndian(bytes);
|
||||
}
|
||||
|
||||
public virtual async ValueTask<uint> ReadUInt32Async(
|
||||
public async ValueTask<uint> ReadUInt32Async(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
CurrentReadByteCount += 4;
|
||||
var bytes = new byte[4];
|
||||
await _reader.ReadBytesAsync(bytes, 0, 4, cancellationToken).ConfigureAwait(false);
|
||||
var bytes = await ReadBytesAsync( 4, cancellationToken).ConfigureAwait(false);
|
||||
return BinaryPrimitives.ReadUInt32LittleEndian(bytes);
|
||||
}
|
||||
|
||||
|
|
@ -70,8 +68,7 @@ internal class AsyncMarkingBinaryReader
|
|||
)
|
||||
{
|
||||
CurrentReadByteCount += 8;
|
||||
var bytes = new byte[8];
|
||||
await _reader.ReadBytesAsync(bytes, 0, 8, cancellationToken).ConfigureAwait(false);
|
||||
var bytes = await ReadBytesAsync( 8, cancellationToken).ConfigureAwait(false);
|
||||
return BinaryPrimitives.ReadUInt64LittleEndian(bytes);
|
||||
}
|
||||
|
||||
|
|
@ -80,8 +77,7 @@ internal class AsyncMarkingBinaryReader
|
|||
)
|
||||
{
|
||||
CurrentReadByteCount += 2;
|
||||
var bytes = new byte[2];
|
||||
await _reader.ReadBytesAsync(bytes, 0, 2, cancellationToken).ConfigureAwait(false);
|
||||
var bytes = await ReadBytesAsync(2, cancellationToken).ConfigureAwait(false);
|
||||
return BinaryPrimitives.ReadInt16LittleEndian(bytes);
|
||||
}
|
||||
|
||||
|
|
@ -90,8 +86,7 @@ internal class AsyncMarkingBinaryReader
|
|||
)
|
||||
{
|
||||
CurrentReadByteCount += 4;
|
||||
var bytes = new byte[4];
|
||||
await _reader.ReadBytesAsync(bytes, 0, 4, cancellationToken).ConfigureAwait(false);
|
||||
var bytes = await ReadBytesAsync( 4, cancellationToken).ConfigureAwait(false);
|
||||
return BinaryPrimitives.ReadInt32LittleEndian(bytes);
|
||||
}
|
||||
|
||||
|
|
@ -100,8 +95,7 @@ internal class AsyncMarkingBinaryReader
|
|||
)
|
||||
{
|
||||
CurrentReadByteCount += 8;
|
||||
var bytes = new byte[8];
|
||||
await _reader.ReadBytesAsync(bytes, 0, 8, cancellationToken).ConfigureAwait(false);
|
||||
var bytes = await ReadBytesAsync(8, cancellationToken).ConfigureAwait(false);
|
||||
return BinaryPrimitives.ReadInt64LittleEndian(bytes);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,13 +6,10 @@ using SharpCompress.Compressors.Rar;
|
|||
|
||||
namespace SharpCompress.Common.Rar;
|
||||
|
||||
internal class AsyncRarCrcBinaryReader : AsyncMarkingBinaryReader
|
||||
internal class AsyncRarCrcBinaryReader(Stream stream) : AsyncMarkingBinaryReader(stream)
|
||||
{
|
||||
private uint _currentCrc;
|
||||
|
||||
public AsyncRarCrcBinaryReader(Stream stream)
|
||||
: base(stream) { }
|
||||
|
||||
public uint GetCrc32() => ~_currentCrc;
|
||||
|
||||
public void ResetCrc() => _currentCrc = 0xffffffff;
|
||||
|
|
|
|||
|
|
@ -10,22 +10,27 @@ namespace SharpCompress.Common.Rar;
|
|||
|
||||
internal sealed class AsyncRarCryptoBinaryReader : AsyncRarCrcBinaryReader
|
||||
{
|
||||
private BlockTransformer _rijndael;
|
||||
private BlockTransformer _rijndael = default!;
|
||||
private readonly Queue<byte> _data = new();
|
||||
private long _readCount;
|
||||
|
||||
public AsyncRarCryptoBinaryReader(Stream stream, ICryptKey cryptKey)
|
||||
private AsyncRarCryptoBinaryReader(Stream stream)
|
||||
: base(stream)
|
||||
{
|
||||
var salt = base.ReadBytesNoCrcAsync(EncryptionConstV5.SIZE_SALT30, CancellationToken.None)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
_readCount += EncryptionConstV5.SIZE_SALT30;
|
||||
_rijndael = new BlockTransformer(cryptKey.Transformer(salt));
|
||||
}
|
||||
|
||||
public AsyncRarCryptoBinaryReader(Stream stream, ICryptKey cryptKey, byte[] salt)
|
||||
: base(stream) => _rijndael = new BlockTransformer(cryptKey.Transformer(salt));
|
||||
public static async ValueTask<AsyncRarCryptoBinaryReader> Create(Stream stream, ICryptKey cryptKey, byte[]? salt = null)
|
||||
{
|
||||
var binary = new AsyncRarCryptoBinaryReader(stream);
|
||||
if (salt == null)
|
||||
{
|
||||
salt = await binary.ReadBytesAsync(EncryptionConstV5.SIZE_SALT30);
|
||||
binary._readCount += EncryptionConstV5.SIZE_SALT30;
|
||||
}
|
||||
binary._rijndael = new BlockTransformer(cryptKey.Transformer(salt));
|
||||
return binary;
|
||||
}
|
||||
|
||||
|
||||
public override long CurrentReadByteCount
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ internal sealed class ArchiveHeader : RarHeader
|
|||
VolumeNumber = (int)
|
||||
await reader.ReadRarVIntUInt32Async(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
// later: we may have a locator record if we need it
|
||||
//if (ExtraSize != 0) {
|
||||
// ReadLocator(reader);
|
||||
//}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -97,12 +97,12 @@ public class RarHeaderFactory
|
|||
_cryptInfo.ReadInitV(new MarkingBinaryReader(stream));
|
||||
var _headerKey = new CryptKey5(Options.Password!, _cryptInfo);
|
||||
|
||||
reader = new RarCryptoBinaryReader(stream, _headerKey, _cryptInfo.Salt);
|
||||
reader = RarCryptoBinaryReader.Create(stream, _headerKey, _cryptInfo.Salt);
|
||||
}
|
||||
else
|
||||
{
|
||||
var key = new CryptKey3(Options.Password);
|
||||
reader = new RarCryptoBinaryReader(stream, key);
|
||||
reader = RarCryptoBinaryReader.Create(stream, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -258,12 +258,12 @@ public class RarHeaderFactory
|
|||
_cryptInfo.ReadInitV(new AsyncMarkingBinaryReader(stream));
|
||||
var _headerKey = new CryptKey5(Options.Password!, _cryptInfo);
|
||||
|
||||
reader = new AsyncRarCryptoBinaryReader(stream, _headerKey, _cryptInfo.Salt);
|
||||
reader = await AsyncRarCryptoBinaryReader.Create(stream, _headerKey, _cryptInfo.Salt);
|
||||
}
|
||||
else
|
||||
{
|
||||
var key = new CryptKey3(Options.Password);
|
||||
reader = new AsyncRarCryptoBinaryReader(stream, key);
|
||||
reader = await AsyncRarCryptoBinaryReader.Create(stream, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#nullable disable
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
|
@ -9,20 +9,26 @@ namespace SharpCompress.Common.Rar;
|
|||
|
||||
internal sealed class RarCryptoBinaryReader : RarCrcBinaryReader
|
||||
{
|
||||
private BlockTransformer _rijndael;
|
||||
private BlockTransformer _rijndael = default!;
|
||||
private readonly Queue<byte> _data = new();
|
||||
private long _readCount;
|
||||
|
||||
public RarCryptoBinaryReader(Stream stream, ICryptKey cryptKey)
|
||||
private RarCryptoBinaryReader(Stream stream)
|
||||
: base(stream)
|
||||
{
|
||||
var salt = base.ReadBytes(EncryptionConstV5.SIZE_SALT30);
|
||||
_readCount += EncryptionConstV5.SIZE_SALT30;
|
||||
_rijndael = new BlockTransformer(cryptKey.Transformer(salt));
|
||||
}
|
||||
|
||||
public RarCryptoBinaryReader(Stream stream, ICryptKey cryptKey, byte[] salt)
|
||||
: base(stream) => _rijndael = new BlockTransformer(cryptKey.Transformer(salt));
|
||||
public static RarCryptoBinaryReader Create(Stream stream, ICryptKey cryptKey, byte[]? salt = null)
|
||||
{
|
||||
var binary = new RarCryptoBinaryReader(stream);
|
||||
if (salt == null)
|
||||
{
|
||||
salt = binary.ReadBytes(EncryptionConstV5.SIZE_SALT30);
|
||||
binary._readCount += EncryptionConstV5.SIZE_SALT30;
|
||||
}
|
||||
binary._rijndael = new BlockTransformer(cryptKey.Transformer(salt));
|
||||
return binary;
|
||||
}
|
||||
|
||||
// track read count ourselves rather than using the underlying stream since we buffer
|
||||
public override long CurrentReadByteCount
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -75,10 +76,10 @@ public abstract class RarVolume : Volume
|
|||
}
|
||||
}
|
||||
|
||||
internal async IAsyncEnumerable<RarFilePart> GetVolumeFilePartsAsync()
|
||||
internal async IAsyncEnumerable<RarFilePart> GetVolumeFilePartsAsync([EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
MarkHeader? lastMarkHeader = null;
|
||||
await foreach (var header in _headerFactory.ReadHeadersAsync(Stream))
|
||||
await foreach (var header in _headerFactory.ReadHeadersAsync(Stream).WithCancellation(cancellationToken))
|
||||
{
|
||||
switch (header.HeaderType)
|
||||
{
|
||||
|
|
@ -123,11 +124,11 @@ public abstract class RarVolume : Volume
|
|||
if (ArchiveHeader is null)
|
||||
{
|
||||
if (Mode == StreamingMode.Streaming)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"ArchiveHeader should never been null in a streaming read."
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream
|
||||
GetVolumeFileParts().First();
|
||||
|
|
@ -173,6 +174,12 @@ public abstract class RarVolume : Volume
|
|||
}
|
||||
}
|
||||
|
||||
public async ValueTask<bool> IsSolidArchiveAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await EnsureArchiveHeaderLoadedAsync(cancellationToken);
|
||||
return ArchiveHeader?.IsSolid ?? false;
|
||||
}
|
||||
|
||||
public int MinVersion
|
||||
{
|
||||
get
|
||||
|
|
@ -221,5 +228,68 @@ public abstract class RarVolume : Volume
|
|||
}
|
||||
}
|
||||
|
||||
private async ValueTask EnsureArchiveHeaderLoadedAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (ArchiveHeader is null)
|
||||
{
|
||||
if (Mode == StreamingMode.Streaming)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"ArchiveHeader should never been null in a streaming read."
|
||||
);
|
||||
}
|
||||
|
||||
// we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream
|
||||
await GetVolumeFilePartsAsync(cancellationToken).FirstAsync();
|
||||
Stream.Position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async ValueTask<int> MinVersionAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
await EnsureArchiveHeaderLoadedAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (_maxCompressionAlgorithm >= 50)
|
||||
{
|
||||
return 5; //5-6
|
||||
}
|
||||
else if (_maxCompressionAlgorithm >= 29)
|
||||
{
|
||||
return 3; //3-4
|
||||
}
|
||||
else if (_maxCompressionAlgorithm >= 20)
|
||||
{
|
||||
return 2; //2
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async ValueTask<int> MaxVersionAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
await EnsureArchiveHeaderLoadedAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (_maxCompressionAlgorithm >= 50)
|
||||
{
|
||||
return 6; //5-6
|
||||
}
|
||||
else if (_maxCompressionAlgorithm >= 29)
|
||||
{
|
||||
return 4; //3-4
|
||||
}
|
||||
else if (_maxCompressionAlgorithm >= 20)
|
||||
{
|
||||
return 2; //2
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public string? Comment { get; internal set; }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue