diff --git a/src/SharpCompress/BufferPool.cs b/src/SharpCompress/BufferPool.cs new file mode 100644 index 00000000..52699536 --- /dev/null +++ b/src/SharpCompress/BufferPool.cs @@ -0,0 +1,33 @@ +using System.Buffers; + +namespace SharpCompress; + +internal static class BufferPool +{ + /// + /// Gets a buffer. + /// + /// Size of 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 the buffer. + /// + /// The buffer. + 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/RarStream.cs b/src/SharpCompress/Compressors/Rar/RarStream.cs index cebc81a1..bf5d3209 100644 --- a/src/SharpCompress/Compressors/Rar/RarStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarStream.cs @@ -14,7 +14,7 @@ internal class RarStream : Stream private bool fetch; - private byte[] tmpBuffer = new byte[65536]; + private byte[] tmpBuffer = BufferPool.Rent(65536); private int tmpOffset; private int tmpCount; @@ -40,6 +40,11 @@ protected override void Dispose(bool disposing) { if (!isDisposed) { + if (disposing) + { + BufferPool.Return(this.tmpBuffer); + this.tmpBuffer = null; + } isDisposed = true; base.Dispose(disposing); readStream.Dispose(); @@ -118,16 +123,7 @@ public override void Write(byte[] buffer, int offset, int count) } if (count > 0) { - if (tmpBuffer.Length < tmpCount + count) - { - var newBuffer = new byte[ - tmpBuffer.Length * 2 > tmpCount + count - ? tmpBuffer.Length * 2 - : tmpCount + count - ]; - Buffer.BlockCopy(tmpBuffer, 0, newBuffer, 0, tmpCount); - tmpBuffer = newBuffer; - } + EnsureBufferCapacity(count); Buffer.BlockCopy(buffer, offset, tmpBuffer, tmpCount, count); tmpCount += count; tmpOffset = 0; @@ -138,4 +134,20 @@ public override void Write(byte[] buffer, int offset, int count) unpack.Suspended = false; } } + + private void EnsureBufferCapacity(int count) + { + if (this.tmpBuffer.Length < this.tmpCount + count) + { + var newLength = + this.tmpBuffer.Length * 2 > this.tmpCount + count + ? this.tmpBuffer.Length * 2 + : this.tmpCount + count; + var newBuffer = BufferPool.Rent(newLength); + Buffer.BlockCopy(this.tmpBuffer, 0, newBuffer, 0, this.tmpCount); + var oldBuffer = this.tmpBuffer; + this.tmpBuffer = newBuffer; + BufferPool.Return(oldBuffer); + } + } } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs index 450b4694..22fdc746 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using SharpCompress.Common.Rar.Headers; #if !Rar2017_64bit @@ -67,15 +67,15 @@ public void DoUnpack() private void UnstoreFile() { - var b = new byte[0x10000]; + Span b = stackalloc byte[(int)Math.Min(0x10000, DestUnpSize)]; do { - var n = readStream.Read(b, 0, (int)Math.Min(b.Length, DestUnpSize)); + var n = readStream.Read(b); if (n == 0) { break; } - writeStream.Write(b, 0, n); + writeStream.Write(b.Slice(0, n)); DestUnpSize -= n; } while (!Suspended); } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs index 397fd334..51dbff0b 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack20_cpp.cs @@ -373,8 +373,8 @@ private void UnpWriteBuf20() private bool ReadTables20() { - var BitLength = new byte[BC20]; - var Table = new byte[MC20 * 4]; + Span BitLength = stackalloc byte[checked((int)BC20)]; + Span Table = stackalloc byte[checked((int)MC20 * 4)]; if (Inp.InAddr > ReadTop - 25) { if (!UnpReadBuf()) @@ -410,13 +410,13 @@ private bool ReadTables20() TableSize = NC20 + DC20 + RC20; } - for (uint I = 0; I < BC20; I++) + for (int I = 0; I < checked((int)BC20); I++) { BitLength[I] = (byte)(Inp.getbits() >> 12); Inp.addbits(4); } MakeDecodeTables(BitLength, 0, BlockTables.BD, BC20); - for (uint I = 0; I < TableSize; ) + for (int I = 0; I < checked((int)TableSize); ) { if (Inp.InAddr > ReadTop - 5) { @@ -487,8 +487,7 @@ private bool ReadTables20() MakeDecodeTables(Table, (int)NC20, BlockTables.DD, DC20); MakeDecodeTables(Table, (int)(NC20 + DC20), BlockTables.RD, RC20); } - //x memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); - Array.Copy(Table, UnpOldTable20, UnpOldTable20.Length); + Table.CopyTo(this.UnpOldTable20); return true; } diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs index 82294e27..62567888 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack50_cpp.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System; using static SharpCompress.Compressors.Rar.UnpackV2017.PackDef; @@ -752,8 +752,8 @@ ref UnpackBlockTables Tables } } - var BitLength = new byte[BC]; - for (uint I = 0; I < BC; I++) + Span BitLength = stackalloc byte[checked((int)BC)]; + for (int I = 0; I < BC; I++) { uint Length = (byte)(Inp.fgetbits() >> 12); Inp.faddbits(4); @@ -784,9 +784,9 @@ ref UnpackBlockTables Tables MakeDecodeTables(BitLength, 0, Tables.BD, BC); - var Table = new byte[HUFF_TABLE_SIZE]; - const uint TableSize = HUFF_TABLE_SIZE; - for (uint I = 0; I < TableSize; ) + Span Table = stackalloc byte[checked((int)HUFF_TABLE_SIZE)]; + const int TableSize = checked((int)HUFF_TABLE_SIZE); + for (int I = 0; I < TableSize; ) { if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 5) { diff --git a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs index 38c21c9f..9c6cbeb0 100644 --- a/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs +++ b/src/SharpCompress/Compressors/Rar/UnpackV2017/Unpack.unpack_cpp.cs @@ -259,7 +259,7 @@ private void UnpInitData(bool Solid) // LengthTable contains the length in bits for every element of alphabet. // Dec is the structure to decode Huffman code/ // Size is size of length table and DecodeNum field in Dec structure, - private void MakeDecodeTables(byte[] LengthTable, int offset, DecodeTable Dec, uint Size) + private void MakeDecodeTables(Span LengthTable, int offset, DecodeTable Dec, uint Size) { // Size of alphabet and DecodePos array. Dec.MaxNum = Size; @@ -269,7 +269,7 @@ private void MakeDecodeTables(byte[] LengthTable, int offset, DecodeTable Dec, u //memset(LengthCount,0,sizeof(LengthCount)); for (size_t I = 0; I < Size; I++) { - LengthCount[LengthTable[offset + I] & 0xf]++; + LengthCount[LengthTable[checked((int)(offset + I))] & 0xf]++; } // We must not calculate the number of zero length codes. @@ -318,7 +318,7 @@ private void MakeDecodeTables(byte[] LengthTable, int offset, DecodeTable Dec, u for (uint I = 0; I < Size; I++) { // Get the current bit length. - var _CurBitLength = (byte)(LengthTable[offset + I] & 0xf); + var _CurBitLength = (byte)(LengthTable[checked((int)(offset + I))] & 0xf); if (_CurBitLength != 0) {