mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-22 23:15:20 +00:00
more 7z async
This commit is contained in:
@@ -129,7 +129,7 @@ public partial class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, Sev
|
||||
DiagnosticsEnabled ? _currentFolderStream : null;
|
||||
|
||||
internal SevenZipReader(ReaderOptions readerOptions, SevenZipArchive archive)
|
||||
: base(readerOptions, ArchiveType.SevenZip) => this._archive = archive;
|
||||
: base(readerOptions, ArchiveType.SevenZip, false) => this._archive = archive;
|
||||
|
||||
public override SevenZipVolume Volume => _archive.Volumes.Single();
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry
|
||||
|
||||
public Stream OpenEntryStream() => FilePart.GetCompressedStream();
|
||||
|
||||
public ValueTask<Stream> OpenEntryStreamAsync(CancellationToken cancellationToken = default) =>
|
||||
new(OpenEntryStream());
|
||||
public async ValueTask<Stream> OpenEntryStreamAsync(CancellationToken cancellationToken = default) => (await FilePart.GetCompressedStreamAsync(cancellationToken)).NotNull();
|
||||
|
||||
public IArchive Archive { get; }
|
||||
|
||||
|
||||
40
src/SharpCompress/Common/SevenZip/ArchiveDatabase.Async.cs
Normal file
40
src/SharpCompress/Common/SevenZip/ArchiveDatabase.Async.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
#nullable disable
|
||||
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip;
|
||||
|
||||
internal sealed partial class ArchiveDatabase
|
||||
{
|
||||
internal async ValueTask<Stream> GetFolderStreamAsync(
|
||||
Stream stream,
|
||||
CFolder folder,
|
||||
IPasswordProvider pw,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var packStreamIndex = folder._firstPackStreamId;
|
||||
var folderStartPackPos = GetFolderStreamPos(folder, 0);
|
||||
var count = folder._packStreams.Count;
|
||||
var packSizes = new long[count];
|
||||
for (var j = 0; j < count; j++)
|
||||
{
|
||||
packSizes[j] = _packSizes[packStreamIndex + j];
|
||||
}
|
||||
|
||||
return await DecoderStreamHelper
|
||||
.CreateDecoderStreamAsync(
|
||||
stream,
|
||||
folderStartPackPos,
|
||||
packSizes,
|
||||
folder,
|
||||
pw,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#nullable disable
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -8,7 +8,7 @@ using SharpCompress.Compressors.LZMA.Utilites;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip;
|
||||
|
||||
internal class ArchiveDatabase
|
||||
internal partial class ArchiveDatabase
|
||||
{
|
||||
internal byte _majorVersion;
|
||||
internal byte _minorVersion;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -125,10 +126,12 @@ internal sealed partial class ArchiveReader
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
var dataVector = ReadAndDecodePackedStreams(
|
||||
db._startPositionAfterHeader,
|
||||
db.PasswordProvider
|
||||
);
|
||||
var dataVector = await ReadAndDecodePackedStreamsAsync(
|
||||
db._startPositionAfterHeader,
|
||||
db.PasswordProvider,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// compressed header without content is odd but ok
|
||||
if (dataVector.Count == 0)
|
||||
@@ -150,9 +153,428 @@ internal sealed partial class ArchiveReader
|
||||
}
|
||||
}
|
||||
|
||||
ReadHeader(db, db.PasswordProvider);
|
||||
await ReadHeaderAsync(db, db.PasswordProvider, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
db.Fill();
|
||||
return db;
|
||||
}
|
||||
|
||||
private async ValueTask<List<byte[]>> ReadAndDecodePackedStreamsAsync(
|
||||
long baseOffset,
|
||||
IPasswordProvider pass,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadAndDecodePackedStreamsAsync --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
ReadStreamsInfo(
|
||||
null,
|
||||
out var dataStartPos,
|
||||
out var packSizes,
|
||||
out var packCrCs,
|
||||
out var folders,
|
||||
out var numUnpackStreamsInFolders,
|
||||
out var unpackSizes,
|
||||
out var digests
|
||||
);
|
||||
|
||||
dataStartPos += baseOffset;
|
||||
|
||||
var dataVector = new List<byte[]>(folders.Count);
|
||||
var packIndex = 0;
|
||||
foreach (var folder in folders)
|
||||
{
|
||||
var oldDataStartPos = dataStartPos;
|
||||
var myPackSizes = new long[folder._packStreams.Count];
|
||||
for (var i = 0; i < myPackSizes.Length; i++)
|
||||
{
|
||||
var packSize = packSizes[packIndex + i];
|
||||
myPackSizes[i] = packSize;
|
||||
dataStartPos += packSize;
|
||||
}
|
||||
|
||||
var outStream = await DecoderStreamHelper
|
||||
.CreateDecoderStreamAsync(
|
||||
_stream,
|
||||
oldDataStartPos,
|
||||
myPackSizes,
|
||||
folder,
|
||||
pass,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var unpackSize = checked((int)folder.GetUnpackSize());
|
||||
var data = new byte[unpackSize];
|
||||
await outStream
|
||||
.ReadExactAsync(data, 0, data.Length, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (outStream.ReadByte() >= 0)
|
||||
{
|
||||
throw new InvalidFormatException("Decoded stream is longer than expected.");
|
||||
}
|
||||
dataVector.Add(data);
|
||||
|
||||
if (folder.UnpackCrcDefined)
|
||||
{
|
||||
if (
|
||||
Crc.Finish(Crc.Update(Crc.INIT_CRC, data, 0, unpackSize))
|
||||
!= folder._unpackCrc
|
||||
)
|
||||
{
|
||||
throw new InvalidFormatException(
|
||||
"Decoded stream does not match expected CRC."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataVector;
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask ReadHeaderAsync(
|
||||
ArchiveDatabase db,
|
||||
IPasswordProvider getTextPassword,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadHeaderAsync --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
var type = ReadId();
|
||||
|
||||
if (type == BlockType.ArchiveProperties)
|
||||
{
|
||||
ReadArchiveProperties();
|
||||
type = ReadId();
|
||||
}
|
||||
|
||||
List<byte[]> dataVector = null;
|
||||
if (type == BlockType.AdditionalStreamsInfo)
|
||||
{
|
||||
dataVector = await ReadAndDecodePackedStreamsAsync(
|
||||
db._startPositionAfterHeader,
|
||||
getTextPassword,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
type = ReadId();
|
||||
}
|
||||
|
||||
List<long> unpackSizes;
|
||||
List<uint?> digests;
|
||||
|
||||
if (type == BlockType.MainStreamsInfo)
|
||||
{
|
||||
ReadStreamsInfo(
|
||||
dataVector,
|
||||
out db._dataStartPosition,
|
||||
out db._packSizes,
|
||||
out db._packCrCs,
|
||||
out db._folders,
|
||||
out db._numUnpackStreamsVector,
|
||||
out unpackSizes,
|
||||
out digests
|
||||
);
|
||||
|
||||
db._dataStartPosition += db._startPositionAfterHeader;
|
||||
type = ReadId();
|
||||
}
|
||||
else
|
||||
{
|
||||
unpackSizes = new List<long>(db._folders.Count);
|
||||
digests = new List<uint?>(db._folders.Count);
|
||||
db._numUnpackStreamsVector = new List<int>(db._folders.Count);
|
||||
for (var i = 0; i < db._folders.Count; i++)
|
||||
{
|
||||
var folder = db._folders[i];
|
||||
unpackSizes.Add(folder.GetUnpackSize());
|
||||
digests.Add(folder._unpackCrc);
|
||||
db._numUnpackStreamsVector.Add(1);
|
||||
}
|
||||
}
|
||||
|
||||
db._files.Clear();
|
||||
|
||||
if (type == BlockType.End)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != BlockType.FilesInfo)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
var numFiles = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumFiles: " + numFiles);
|
||||
#endif
|
||||
db._files = new List<CFileItem>(numFiles);
|
||||
for (var i = 0; i < numFiles; i++)
|
||||
{
|
||||
db._files.Add(new CFileItem());
|
||||
}
|
||||
|
||||
var emptyStreamVector = new BitVector(numFiles);
|
||||
BitVector emptyFileVector = null;
|
||||
BitVector antiFileVector = null;
|
||||
var numEmptyStreams = 0;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
type = ReadId();
|
||||
if (type == BlockType.End)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var size = checked((long)ReadNumber());
|
||||
var oldPos = _currentReader.Offset;
|
||||
switch (type)
|
||||
{
|
||||
case BlockType.Name:
|
||||
using (var streamSwitch = new CStreamSwitch())
|
||||
{
|
||||
streamSwitch.Set(this, dataVector);
|
||||
#if DEBUG
|
||||
Log.Write("FileNames:");
|
||||
#endif
|
||||
for (var i = 0; i < db._files.Count; i++)
|
||||
{
|
||||
db._files[i].Name = _currentReader.ReadString();
|
||||
#if DEBUG
|
||||
Log.Write(" " + db._files[i].Name);
|
||||
#endif
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case BlockType.WinAttributes:
|
||||
#if DEBUG
|
||||
Log.Write("WinAttributes:");
|
||||
#endif
|
||||
ReadAttributeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, uint? attr)
|
||||
{
|
||||
db._files[i].ExtendedAttrib = attr;
|
||||
|
||||
if (attr.HasValue && (attr.Value >> 16) != 0)
|
||||
{
|
||||
attr = attr.Value & 0x7FFFu;
|
||||
}
|
||||
|
||||
db._files[i].Attrib = attr;
|
||||
#if DEBUG
|
||||
Log.Write(
|
||||
" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a")
|
||||
);
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.EmptyStream:
|
||||
emptyStreamVector = ReadBitVector(numFiles);
|
||||
#if DEBUG
|
||||
|
||||
Log.Write("EmptyStream: ");
|
||||
#endif
|
||||
for (var i = 0; i < emptyStreamVector.Length; i++)
|
||||
{
|
||||
if (emptyStreamVector[i])
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write("x");
|
||||
#endif
|
||||
numEmptyStreams++;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write(".");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
|
||||
emptyFileVector = new BitVector(numEmptyStreams);
|
||||
antiFileVector = new BitVector(numEmptyStreams);
|
||||
break;
|
||||
case BlockType.EmptyFile:
|
||||
emptyFileVector = ReadBitVector(numEmptyStreams);
|
||||
#if DEBUG
|
||||
Log.Write("EmptyFile: ");
|
||||
for (var i = 0; i < numEmptyStreams; i++)
|
||||
{
|
||||
Log.Write(emptyFileVector[i] ? "x" : ".");
|
||||
}
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.Anti:
|
||||
antiFileVector = ReadBitVector(numEmptyStreams);
|
||||
#if DEBUG
|
||||
Log.Write("Anti: ");
|
||||
for (var i = 0; i < numEmptyStreams; i++)
|
||||
{
|
||||
Log.Write(antiFileVector[i] ? "x" : ".");
|
||||
}
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.StartPos:
|
||||
#if DEBUG
|
||||
Log.Write("StartPos:");
|
||||
#endif
|
||||
ReadNumberVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, long? startPos)
|
||||
{
|
||||
db._files[i].StartPos = startPos;
|
||||
#if DEBUG
|
||||
Log.Write(
|
||||
" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a")
|
||||
);
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.CTime:
|
||||
#if DEBUG
|
||||
Log.Write("CTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].CTime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.ATime:
|
||||
#if DEBUG
|
||||
Log.Write("ATime:");
|
||||
#endif
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].ATime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.MTime:
|
||||
#if DEBUG
|
||||
Log.Write("MTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].MTime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.Dummy:
|
||||
#if DEBUG
|
||||
Log.Write("Dummy: " + size);
|
||||
#endif
|
||||
for (long j = 0; j < size; j++)
|
||||
{
|
||||
if (ReadByte() != 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SkipData(size);
|
||||
break;
|
||||
}
|
||||
|
||||
var checkRecordsSize = (db._majorVersion > 0 || db._minorVersion > 2);
|
||||
if (checkRecordsSize && _currentReader.Offset - oldPos != size)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
var emptyFileIndex = 0;
|
||||
var sizeIndex = 0;
|
||||
for (var i = 0; i < numFiles; i++)
|
||||
{
|
||||
var file = db._files[i];
|
||||
file.HasStream = !emptyStreamVector[i];
|
||||
if (file.HasStream)
|
||||
{
|
||||
file.IsDir = false;
|
||||
file.IsAnti = false;
|
||||
file.Size = unpackSizes[sizeIndex];
|
||||
file.Crc = digests[sizeIndex];
|
||||
sizeIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.IsDir = !emptyFileVector[emptyFileIndex];
|
||||
file.IsAnti = antiFileVector[emptyFileIndex];
|
||||
emptyFileIndex++;
|
||||
file.Size = 0;
|
||||
file.Crc = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.SevenZip;
|
||||
@@ -58,6 +60,28 @@ internal class SevenZipFilePart : FilePart
|
||||
return new ReadOnlySubStream(folderStream, Header.Size, leaveOpen: false);
|
||||
}
|
||||
|
||||
internal override async ValueTask<Stream?> GetCompressedStreamAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!Header.HasStream)
|
||||
{
|
||||
return Stream.Null;
|
||||
}
|
||||
var folderStream = await _database.GetFolderStreamAsync(_stream, Folder!, _database.PasswordProvider, cancellationToken);
|
||||
|
||||
var firstFileIndex = _database._folderStartFileIndex[_database._folders.IndexOf(Folder!)];
|
||||
var skipCount = Index - firstFileIndex;
|
||||
long skipSize = 0;
|
||||
for (var i = 0; i < skipCount; i++)
|
||||
{
|
||||
skipSize += _database._files[firstFileIndex + i].Size;
|
||||
}
|
||||
if (skipSize > 0)
|
||||
{
|
||||
await folderStream.SkipAsync(skipSize, cancellationToken);
|
||||
}
|
||||
return new ReadOnlySubStream(folderStream, Header.Size, leaveOpen: false);
|
||||
}
|
||||
|
||||
public CompressionType CompressionType
|
||||
{
|
||||
get
|
||||
|
||||
@@ -23,24 +23,8 @@ internal sealed partial class StreamingZipHeaderFactory : ZipHeaderFactory
|
||||
|
||||
internal IEnumerable<ZipHeader> ReadStreamHeader(Stream stream)
|
||||
{
|
||||
if (stream is not SharpCompressStream) //ensure the stream is already a SharpCompressStream. So the buffer/size will already be set
|
||||
{
|
||||
//the original code wrapped this with RewindableStream. Wrap with SharpCompressStream as we can get the buffer size
|
||||
if (stream is SourceStream src)
|
||||
{
|
||||
stream = new SharpCompressStream(
|
||||
stream,
|
||||
src.ReaderOptions.LeaveStreamOpen,
|
||||
bufferSize: src.ReaderOptions.BufferSize
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Stream must be a SharpCompressStream", nameof(stream));
|
||||
}
|
||||
}
|
||||
var rewindableStream = (SharpCompressStream)stream;
|
||||
|
||||
//the original code wrapped this with RewindableStream. Wrap with SharpCompressStream as we can get the buffer size
|
||||
var rewindableStream = stream;
|
||||
while (true)
|
||||
{
|
||||
var reader = new BinaryReader(rewindableStream);
|
||||
|
||||
74
src/SharpCompress/Compressors/LZMA/DecoderRegistry.Async.cs
Normal file
74
src/SharpCompress/Compressors/LZMA/DecoderRegistry.Async.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.SevenZip;
|
||||
using SharpCompress.Compressors.BZip2;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Compressors.Filters;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
using SharpCompress.Compressors.PPMd;
|
||||
using SharpCompress.Compressors.ZStandard;
|
||||
|
||||
namespace SharpCompress.Compressors.LZMA;
|
||||
|
||||
internal static partial class DecoderRegistry
|
||||
{
|
||||
internal static async ValueTask<Stream> CreateDecoderStreamAsync(
|
||||
CMethodId id,
|
||||
Stream[] inStreams,
|
||||
byte[] info,
|
||||
IPasswordProvider pass,
|
||||
long limit,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
switch (id._id)
|
||||
{
|
||||
case K_COPY:
|
||||
if (info != null)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
return inStreams.Single();
|
||||
case K_DELTA:
|
||||
return new DeltaFilter(false, inStreams.Single(), info);
|
||||
case K_LZMA:
|
||||
case K_LZMA2:
|
||||
return await LzmaStream
|
||||
.CreateAsync(info, inStreams.Single(), -1, limit, null, info.Length < 5, false)
|
||||
.ConfigureAwait(false);
|
||||
case CMethodId.K_AES_ID:
|
||||
return new AesDecoderStream(inStreams.Single(), info, pass, limit);
|
||||
case K_BCJ:
|
||||
return new BCJFilter(false, inStreams.Single());
|
||||
case K_BCJ2:
|
||||
return new Bcj2DecoderStream(inStreams, info, limit);
|
||||
case K_PPC:
|
||||
return new BCJFilterPPC(false, inStreams.Single());
|
||||
case K_IA64:
|
||||
return new BCJFilterIA64(false, inStreams.Single());
|
||||
case K_ARM:
|
||||
return new BCJFilterARM(false, inStreams.Single());
|
||||
case K_ARMT:
|
||||
return new BCJFilterARMT(false, inStreams.Single());
|
||||
case K_SPARC:
|
||||
return new BCJFilterSPARC(false, inStreams.Single());
|
||||
case K_ARM64:
|
||||
return new BCJFilterARM64(false, inStreams.Single());
|
||||
case K_RISCV:
|
||||
return new BCJFilterRISCV(false, inStreams.Single());
|
||||
case K_B_ZIP2:
|
||||
return await BZip2Stream.CreateAsync(inStreams.Single(), CompressionMode.Decompress, true, cancellationToken: cancellationToken);
|
||||
case K_PPMD:
|
||||
return new PpmdStream(new PpmdProperties(info), inStreams.Single(), false);
|
||||
case K_DEFLATE:
|
||||
return new DeflateStream(inStreams.Single(), CompressionMode.Decompress);
|
||||
case K_ZSTD:
|
||||
return new DecompressionStream(inStreams.Single());
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.SevenZip;
|
||||
using SharpCompress.Compressors.LZMA.Utilites;
|
||||
@@ -180,6 +182,99 @@ internal static class DecoderStreamHelper
|
||||
);
|
||||
}
|
||||
|
||||
private static async ValueTask<Stream> CreateDecoderStreamAsync(
|
||||
Stream[] packStreams,
|
||||
long[] packSizes,
|
||||
Stream[] outStreams,
|
||||
CFolder folderInfo,
|
||||
int coderIndex,
|
||||
IPasswordProvider pass,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var coderInfo = folderInfo._coders[coderIndex];
|
||||
if (coderInfo._numOutStreams != 1)
|
||||
{
|
||||
throw new NotSupportedException("Multiple output streams are not supported.");
|
||||
}
|
||||
|
||||
var inStreamId = 0;
|
||||
for (var i = 0; i < coderIndex; i++)
|
||||
{
|
||||
inStreamId += folderInfo._coders[i]._numInStreams;
|
||||
}
|
||||
|
||||
var outStreamId = 0;
|
||||
for (var i = 0; i < coderIndex; i++)
|
||||
{
|
||||
outStreamId += folderInfo._coders[i]._numOutStreams;
|
||||
}
|
||||
|
||||
var inStreams = new Stream[coderInfo._numInStreams];
|
||||
|
||||
for (var i = 0; i < inStreams.Length; i++, inStreamId++)
|
||||
{
|
||||
var bindPairIndex = folderInfo.FindBindPairForInStream(inStreamId);
|
||||
if (bindPairIndex >= 0)
|
||||
{
|
||||
var pairedOutIndex = folderInfo._bindPairs[bindPairIndex]._outIndex;
|
||||
|
||||
if (outStreams[pairedOutIndex] != null)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
"Overlapping stream bindings are not supported."
|
||||
);
|
||||
}
|
||||
|
||||
var otherCoderIndex = FindCoderIndexForOutStreamIndex(folderInfo, pairedOutIndex);
|
||||
inStreams[i] = await CreateDecoderStreamAsync(
|
||||
packStreams,
|
||||
packSizes,
|
||||
outStreams,
|
||||
folderInfo,
|
||||
otherCoderIndex,
|
||||
pass,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
//inStreamSizes[i] = folderInfo.UnpackSizes[pairedOutIndex];
|
||||
|
||||
if (outStreams[pairedOutIndex] != null)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
"Overlapping stream bindings are not supported."
|
||||
);
|
||||
}
|
||||
|
||||
outStreams[pairedOutIndex] = inStreams[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = folderInfo.FindPackStreamArrayIndex(inStreamId);
|
||||
if (index < 0)
|
||||
{
|
||||
throw new NotSupportedException("Could not find input stream binding.");
|
||||
}
|
||||
|
||||
inStreams[i] = packStreams[index];
|
||||
|
||||
//inStreamSizes[i] = packSizes[index];
|
||||
}
|
||||
}
|
||||
|
||||
var unpackSize = folderInfo._unpackSizes[outStreamId];
|
||||
return await DecoderRegistry.CreateDecoderStreamAsync(
|
||||
coderInfo._methodId,
|
||||
inStreams,
|
||||
coderInfo._props,
|
||||
pass,
|
||||
unpackSize,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static Stream CreateDecoderStream(
|
||||
Stream inStream,
|
||||
long startPos,
|
||||
@@ -216,4 +311,44 @@ internal static class DecoderStreamHelper
|
||||
pass
|
||||
);
|
||||
}
|
||||
|
||||
internal static async ValueTask<Stream> CreateDecoderStreamAsync(
|
||||
Stream inStream,
|
||||
long startPos,
|
||||
long[] packSizes,
|
||||
CFolder folderInfo,
|
||||
IPasswordProvider pass,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
if (!folderInfo.CheckStructure())
|
||||
{
|
||||
throw new NotSupportedException("Unsupported stream binding structure.");
|
||||
}
|
||||
|
||||
var inStreams = new Stream[folderInfo._packStreams.Count];
|
||||
for (var j = 0; j < folderInfo._packStreams.Count; j++)
|
||||
{
|
||||
inStreams[j] = new BufferedSubStream(inStream, startPos, packSizes[j]);
|
||||
startPos += packSizes[j];
|
||||
}
|
||||
|
||||
var outStreams = new Stream[folderInfo._unpackSizes.Count];
|
||||
|
||||
FindPrimaryOutStreamIndex(
|
||||
folderInfo,
|
||||
out var primaryCoderIndex,
|
||||
out var primaryOutStreamIndex
|
||||
);
|
||||
return await CreateDecoderStreamAsync(
|
||||
inStreams,
|
||||
packSizes,
|
||||
outStreams,
|
||||
folderInfo,
|
||||
primaryCoderIndex,
|
||||
pass,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public partial class LzmaStream
|
||||
_decoder.SetDecoderProperties(Properties);
|
||||
}
|
||||
|
||||
_rangeDecoder.Init(_inputStream);
|
||||
await _rangeDecoder.InitAsync(_inputStream, cancellationToken);
|
||||
}
|
||||
else if (control > 0x02)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ using SharpCompress.Compressors.ZStandard;
|
||||
|
||||
namespace SharpCompress.Compressors.LZMA;
|
||||
|
||||
internal static class DecoderRegistry
|
||||
internal static partial class DecoderRegistry
|
||||
{
|
||||
private const uint K_COPY = 0x0;
|
||||
private const uint K_DELTA = 0x3;
|
||||
|
||||
@@ -18,10 +18,12 @@ public abstract partial class AbstractReader<TEntry, TVolume> : IReader, IAsyncR
|
||||
private IEnumerator<TEntry>? _entriesForCurrentReadStream;
|
||||
private IAsyncEnumerator<TEntry>? _entriesForCurrentReadStreamAsync;
|
||||
private bool _wroteCurrentEntry;
|
||||
private readonly bool _disposeVolume;
|
||||
|
||||
internal AbstractReader(ReaderOptions options, ArchiveType archiveType)
|
||||
internal AbstractReader(ReaderOptions options, ArchiveType archiveType, bool disposeVolume = true)
|
||||
{
|
||||
ArchiveType = archiveType;
|
||||
_disposeVolume = disposeVolume;
|
||||
Options = options;
|
||||
}
|
||||
|
||||
@@ -56,7 +58,10 @@ public abstract partial class AbstractReader<TEntry, TVolume> : IReader, IAsyncR
|
||||
public virtual void Dispose()
|
||||
{
|
||||
_entriesForCurrentReadStream?.Dispose();
|
||||
Volume?.Dispose();
|
||||
if (_disposeVolume)
|
||||
{
|
||||
Volume?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -44,10 +44,8 @@ public class ArchiveTests : ReaderTests
|
||||
foreach (var path in testArchives)
|
||||
{
|
||||
using (
|
||||
var stream = SharpCompressStream.Create(
|
||||
File.OpenRead(path),
|
||||
leaveOpen: true,
|
||||
throwOnDispose: true
|
||||
var stream = new NonDisposingStream(
|
||||
File.OpenRead(path)
|
||||
)
|
||||
)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user