diff --git a/Directory.Packages.props b/Directory.Packages.props index 09060b11..498bf1b5 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,6 +7,7 @@ + @@ -15,4 +16,4 @@ - + \ No newline at end of file diff --git a/src/SharpCompress/Archives/Rar/RarArchive.cs b/src/SharpCompress/Archives/Rar/RarArchive.cs index a05ad417..6a5c9781 100644 --- a/src/SharpCompress/Archives/Rar/RarArchive.cs +++ b/src/SharpCompress/Archives/Rar/RarArchive.cs @@ -14,6 +14,7 @@ namespace SharpCompress.Archives.Rar; public class RarArchive : AbstractArchive { + private bool _disposed; internal Lazy UnpackV2017 { get; } = new(() => new Compressors.Rar.UnpackV2017.Unpack()); internal Lazy UnpackV1 { get; } = new(() => new Compressors.Rar.UnpackV1.Unpack()); @@ -25,6 +26,20 @@ public class RarArchive : AbstractArchive private RarArchive(SourceStream sourceStream) : base(ArchiveType.Rar, sourceStream) { } + public override void Dispose() + { + if (!_disposed) + { + if (UnpackV1.IsValueCreated && UnpackV1.Value is IDisposable unpackV1) + { + unpackV1.Dispose(); + } + + _disposed = true; + base.Dispose(); + } + } + protected override IEnumerable LoadEntries(IEnumerable volumes) => RarArchiveEntryFactory.GetEntries(this, volumes, ReaderOptions); diff --git a/src/SharpCompress/BufferPool.cs b/src/SharpCompress/BufferPool.cs deleted file mode 100644 index 895edc86..00000000 --- a/src/SharpCompress/BufferPool.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Buffers; - -namespace SharpCompress.Helpers; - -internal static class BufferPool -{ - /// - /// gets a buffer from the pool - /// - /// size of the buffer - /// the buffer - public static byte[] Rent(int bufferSize) - { -#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER - return ArrayPool.Shared.Rent(bufferSize); -#else - return new byte[bufferSize]; -#endif - } - - /// - /// returns a buffer to the pool - /// - /// the buffer to return - public static void Return(byte[] buffer) - { -#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER - ArrayPool.Shared.Return(buffer); -#else - // no-op -#endif - } -} diff --git a/src/SharpCompress/Compressors/Rar/RarCRC.cs b/src/SharpCompress/Compressors/Rar/RarCRC.cs index 8f4fb47e..7e6fc6cc 100644 --- a/src/SharpCompress/Compressors/Rar/RarCRC.cs +++ b/src/SharpCompress/Compressors/Rar/RarCRC.cs @@ -9,7 +9,7 @@ internal static class RarCRC public static uint CheckCrc(uint startCrc, byte b) => (crcTab[((int)startCrc ^ b) & 0xff] ^ (startCrc >> 8)); - public static uint CheckCrc(uint startCrc, byte[] data, int offset, int count) + public static uint CheckCrc(uint startCrc, ReadOnlySpan data, int offset, int count) { var size = Math.Min(data.Length - offset, count); diff --git a/src/SharpCompress/Compressors/Rar/RarStream.cs b/src/SharpCompress/Compressors/Rar/RarStream.cs index bf5d3209..073fcaa0 100644 --- a/src/SharpCompress/Compressors/Rar/RarStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarStream.cs @@ -1,6 +1,7 @@ #nullable disable using System; +using System.Buffers; using System.IO; using SharpCompress.Common.Rar.Headers; @@ -14,7 +15,7 @@ internal class RarStream : Stream private bool fetch; - private byte[] tmpBuffer = BufferPool.Rent(65536); + private byte[] tmpBuffer = ArrayPool.Shared.Rent(65536); private int tmpOffset; private int tmpCount; @@ -42,7 +43,7 @@ internal class RarStream : Stream { if (disposing) { - BufferPool.Return(this.tmpBuffer); + ArrayPool.Shared.Return(this.tmpBuffer); this.tmpBuffer = null; } isDisposed = true; @@ -143,11 +144,11 @@ internal class RarStream : Stream this.tmpBuffer.Length * 2 > this.tmpCount + count ? this.tmpBuffer.Length * 2 : this.tmpCount + count; - var newBuffer = BufferPool.Rent(newLength); + var newBuffer = ArrayPool.Shared.Rent(newLength); Buffer.BlockCopy(this.tmpBuffer, 0, newBuffer, 0, this.tmpCount); var oldBuffer = this.tmpBuffer; this.tmpBuffer = newBuffer; - BufferPool.Return(oldBuffer); + ArrayPool.Shared.Return(oldBuffer); } } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs index e6d4153d..eb2ddea6 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack.cs @@ -1,6 +1,7 @@ #nullable disable using System; +using System.Buffers; using System.Collections.Generic; using System.IO; using SharpCompress.Common; @@ -12,14 +13,28 @@ using SharpCompress.Compressors.Rar.VM; namespace SharpCompress.Compressors.Rar.UnpackV1; -internal sealed partial class Unpack : BitInput, IRarUnpack +internal sealed partial class Unpack : BitInput, IRarUnpack, IDisposable { private readonly BitInput Inp; + private bool disposed; public Unpack() => // to ease in porting Unpack50.cs Inp = this; + public void Dispose() + { + if (!disposed) + { + if (!externalWindow) + { + ArrayPool.Shared.Return(window); + window = null; + } + disposed = true; + } + } + public bool FileExtracted { get; private set; } public long DestSize @@ -74,7 +89,7 @@ internal sealed partial class Unpack : BitInput, IRarUnpack private BlockTypes unpBlockType; - //private bool externalWindow; + private bool externalWindow; private long writtenFileSize; @@ -111,15 +126,14 @@ internal sealed partial class Unpack : BitInput, IRarUnpack private void Init(byte[] window) { - if (window is null) + if (this.window is null && window is null) { - this.window = new byte[PackDef.MAXWINSIZE]; + this.window = ArrayPool.Shared.Rent(PackDef.MAXWINSIZE); } - else + else if (window is not null) { this.window = window; - - //externalWindow = true; + externalWindow = true; } inAddr = 0; UnpInitData(false); @@ -175,31 +189,24 @@ internal sealed partial class Unpack : BitInput, IRarUnpack private void UnstoreFile() { - var buffer = new byte[0x10000]; - while (true) + Span buffer = stackalloc byte[(int)Math.Min(0x10000, destUnpSize)]; + do { - var code = readStream.Read(buffer, 0, (int)Math.Min(buffer.Length, destUnpSize)); + var code = readStream.Read(buffer); if (code == 0 || code == -1) { break; } code = code < destUnpSize ? code : (int)destUnpSize; - writeStream.Write(buffer, 0, code); - if (destUnpSize >= 0) - { - destUnpSize -= code; - } - if (suspended) - { - return; - } - } + writeStream.Write(buffer.Slice(0, code)); + destUnpSize -= code; + } while (!suspended && destUnpSize > 0); } private void Unpack29(bool solid) { - var DDecode = new int[PackDef.DC]; - var DBits = new byte[PackDef.DC]; + Span DDecode = stackalloc int[PackDef.DC]; + Span DBits = stackalloc byte[PackDef.DC]; int Bits; @@ -859,9 +866,9 @@ internal sealed partial class Unpack : BitInput, IRarUnpack private bool ReadTables() { - var bitLength = new byte[PackDef.BC]; + Span bitLength = stackalloc byte[PackDef.BC]; + Span table = stackalloc byte[PackDef.HUFF_TABLE_SIZE]; - var table = new byte[PackDef.HUFF_TABLE_SIZE]; if (inAddr > readTop - 25) { if (!unpReadBuf()) @@ -989,7 +996,7 @@ internal sealed partial class Unpack : BitInput, IRarUnpack // memcpy(unpOldTable,table,sizeof(unpOldTable)); - Buffer.BlockCopy(table, 0, unpOldTable, 0, unpOldTable.Length); + table.CopyTo(unpOldTable); return (true); } @@ -1190,7 +1197,7 @@ internal sealed partial class Unpack : BitInput, IRarUnpack { return (false); } - var VMCode = new byte[VMCodeSize]; + Span VMCode = stackalloc byte[VMCodeSize]; for (var I = 0; I < VMCodeSize; I++) { if (Inp.Overflow(3)) diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs index 3a5d008d..e4069c76 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/Unpack20.cs @@ -391,8 +391,8 @@ internal partial class Unpack private bool ReadTables20() { - var BitLength = new byte[PackDef.BC20]; - var Table = new byte[PackDef.MC20 * 4]; + Span BitLength = stackalloc byte[PackDef.BC20]; + Span Table = stackalloc byte[PackDef.MC20 * 4]; int TableSize, N, I; diff --git a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs index b501337b..4b16e43d 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV1/UnpackUtility.cs @@ -181,7 +181,12 @@ internal static class UnpackUtility return (dec.DecodeNum[N]); } - internal static void makeDecodeTables(byte[] lenTab, int offset, Decode.Decode dec, int size) + internal static void makeDecodeTables( + Span lenTab, + int offset, + Decode.Decode dec, + int size + ) { Span lenCount = stackalloc int[16]; Span tmpPos = stackalloc int[16]; diff --git a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs index f758b8a4..0dd3e326 100644 --- a/src/SharpCompress/Compressors/Rar/VM/RarVM.cs +++ b/src/SharpCompress/Compressors/Rar/VM/RarVM.cs @@ -776,14 +776,14 @@ internal sealed class RarVM : BitInput } } - public void prepare(byte[] code, int codeSize, VMPreparedProgram prg) + public void prepare(ReadOnlySpan code, int codeSize, VMPreparedProgram prg) { InitBitInput(); var cpLength = Math.Min(MAX_SIZE, codeSize); // memcpy(inBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); - Buffer.BlockCopy(code, 0, InBuf, 0, cpLength); + code.Slice(0, cpLength).CopyTo(InBuf); byte xorSum = 0; for (var i = 1; i < codeSize; i++) { @@ -1105,7 +1105,7 @@ internal sealed class RarVM : BitInput } } - private VMStandardFilters IsStandardFilter(byte[] code, int codeSize) + private VMStandardFilters IsStandardFilter(ReadOnlySpan code, int codeSize) { VMStandardFilterSignature[] stdList = { diff --git a/src/SharpCompress/Readers/AbstractReader.cs b/src/SharpCompress/Readers/AbstractReader.cs index b36acd53..96ac0a58 100644 --- a/src/SharpCompress/Readers/AbstractReader.cs +++ b/src/SharpCompress/Readers/AbstractReader.cs @@ -44,7 +44,7 @@ public abstract class AbstractReader : IReader, IReaderExtracti #region IDisposable Members - public void Dispose() + public virtual void Dispose() { _entriesForCurrentReadStream?.Dispose(); Volume?.Dispose(); diff --git a/src/SharpCompress/Readers/Rar/RarReader.cs b/src/SharpCompress/Readers/Rar/RarReader.cs index 2398cfac..184ba62d 100644 --- a/src/SharpCompress/Readers/Rar/RarReader.cs +++ b/src/SharpCompress/Readers/Rar/RarReader.cs @@ -13,6 +13,7 @@ namespace SharpCompress.Readers.Rar; /// public abstract class RarReader : AbstractReader { + private bool _disposed; private RarVolume? volume; private Lazy UnpackV2017 { get; } = new(() => new Compressors.Rar.UnpackV2017.Unpack()); @@ -21,6 +22,20 @@ public abstract class RarReader : AbstractReader internal RarReader(ReaderOptions options) : base(options, ArchiveType.Rar) { } + public override void Dispose() + { + if (!_disposed) + { + if (UnpackV1.IsValueCreated && UnpackV1.Value is IDisposable unpackV1) + { + unpackV1.Dispose(); + } + + _disposed = true; + base.Dispose(); + } + } + protected abstract void ValidateArchive(RarVolume archive); public override RarVolume? Volume => volume; diff --git a/src/SharpCompress/SharpCompress.csproj b/src/SharpCompress/SharpCompress.csproj index 6b31b2a4..4b4909b7 100644 --- a/src/SharpCompress/SharpCompress.csproj +++ b/src/SharpCompress/SharpCompress.csproj @@ -33,6 +33,7 @@ true + diff --git a/src/SharpCompress/packages.lock.json b/src/SharpCompress/packages.lock.json index d5c6af0b..5b33071a 100644 --- a/src/SharpCompress/packages.lock.json +++ b/src/SharpCompress/packages.lock.json @@ -30,6 +30,12 @@ "Microsoft.SourceLink.Common": "8.0.0" } }, + "System.Buffers": { + "type": "Direct", + "requested": "[4.6.0, )", + "resolved": "4.6.0", + "contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA==" + }, "System.Memory": { "type": "Direct", "requested": "[4.5.5, )", @@ -76,11 +82,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "System.Buffers": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" - }, "System.Numerics.Vectors": { "type": "Transitive", "resolved": "4.5.0", @@ -129,6 +130,12 @@ "Microsoft.NETCore.Platforms": "1.1.0" } }, + "System.Buffers": { + "type": "Direct", + "requested": "[4.6.0, )", + "resolved": "4.6.0", + "contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA==" + }, "System.Memory": { "type": "Direct", "requested": "[4.5.5, )", @@ -175,11 +182,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "System.Buffers": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" - }, "System.Numerics.Vectors": { "type": "Transitive", "resolved": "4.4.0", @@ -216,6 +218,12 @@ "Microsoft.SourceLink.Common": "8.0.0" } }, + "System.Buffers": { + "type": "Direct", + "requested": "[4.6.0, )", + "resolved": "4.6.0", + "contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA==" + }, "System.Text.Encoding.CodePages": { "type": "Direct", "requested": "[8.0.0, )", @@ -245,11 +253,6 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "System.Buffers": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" - }, "System.Numerics.Vectors": { "type": "Transitive", "resolved": "4.4.0", @@ -283,6 +286,12 @@ "Microsoft.SourceLink.Common": "8.0.0" } }, + "System.Buffers": { + "type": "Direct", + "requested": "[4.6.0, )", + "resolved": "4.6.0", + "contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA==" + }, "ZstdSharp.Port": { "type": "Direct", "requested": "[0.8.1, )", @@ -317,6 +326,12 @@ "Microsoft.SourceLink.Common": "8.0.0" } }, + "System.Buffers": { + "type": "Direct", + "requested": "[4.6.0, )", + "resolved": "4.6.0", + "contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA==" + }, "ZstdSharp.Port": { "type": "Direct", "requested": "[0.8.1, )", @@ -335,4 +350,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/SharpCompress.Test/packages.lock.json b/tests/SharpCompress.Test/packages.lock.json index 7e146431..94f193fc 100644 --- a/tests/SharpCompress.Test/packages.lock.json +++ b/tests/SharpCompress.Test/packages.lock.json @@ -97,11 +97,6 @@ "System.Reflection.Metadata": "1.6.0" } }, - "System.Buffers": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" - }, "System.Collections.Immutable": { "type": "Transitive", "resolved": "1.5.0", @@ -182,6 +177,7 @@ "type": "Project", "dependencies": { "Microsoft.Bcl.AsyncInterfaces": "[8.0.0, )", + "System.Buffers": "[4.6.0, )", "System.Memory": "[4.5.5, )", "System.Text.Encoding.CodePages": "[8.0.0, )", "ZstdSharp.Port": "[0.8.1, )" @@ -196,6 +192,12 @@ "System.Threading.Tasks.Extensions": "4.5.4" } }, + "System.Buffers": { + "type": "CentralTransitive", + "requested": "[4.6.0, )", + "resolved": "4.6.0", + "contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA==" + }, "System.Memory": { "type": "CentralTransitive", "requested": "[4.5.5, )", @@ -394,9 +396,16 @@ "sharpcompress": { "type": "Project", "dependencies": { + "System.Buffers": "[4.6.0, )", "ZstdSharp.Port": "[0.8.1, )" } }, + "System.Buffers": { + "type": "CentralTransitive", + "requested": "[4.6.0, )", + "resolved": "4.6.0", + "contentHash": "lN6tZi7Q46zFzAbRYXTIvfXcyvQQgxnY7Xm6C6xQ9784dEL1amjM6S6Iw4ZpsvesAKnRVsM4scrDQaDqSClkjA==" + }, "ZstdSharp.Port": { "type": "CentralTransitive", "requested": "[0.8.1, )",