From 6973436b9459a048ff3014d48c0f3431db1245bb Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 30 Jul 2020 17:29:33 -0700 Subject: [PATCH] Add and use Stream.Write(ReadOnlySpan buffer) polyfill --- .../Archives/GZip/GZipArchive.cs | 7 +++--- .../Compressors/BZip2/BZip2Stream.cs | 19 ++++++++++++-- .../Compressors/Deflate/ZlibBaseStream.cs | 8 +++--- .../Compressors/LZMA/LZipStream.cs | 17 +++++++++++++ src/SharpCompress/Crypto/Crc32Stream.cs | 20 +++++++++++---- .../Polyfills/StreamExtensions.cs | 25 +++++++++++++++++++ src/SharpCompress/Writers/Zip/ZipWriter.cs | 14 +++++------ 7 files changed, 88 insertions(+), 22 deletions(-) create mode 100644 src/SharpCompress/Polyfills/StreamExtensions.cs diff --git a/src/SharpCompress/Archives/GZip/GZipArchive.cs b/src/SharpCompress/Archives/GZip/GZipArchive.cs index ccf170b6..025aacaa 100644 --- a/src/SharpCompress/Archives/GZip/GZipArchive.cs +++ b/src/SharpCompress/Archives/GZip/GZipArchive.cs @@ -77,10 +77,9 @@ namespace SharpCompress.Archives.GZip { return false; } - using (Stream stream = fileInfo.OpenRead()) - { - return IsGZipFile(stream); - } + + using Stream stream = fileInfo.OpenRead(); + return IsGZipFile(stream); } public void SaveTo(string filePath) diff --git a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs index c0f040a9..985d9009 100644 --- a/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs +++ b/src/SharpCompress/Compressors/BZip2/BZip2Stream.cs @@ -1,8 +1,9 @@ -using System.IO; +using System; +using System.IO; namespace SharpCompress.Compressors.BZip2 { - public class BZip2Stream : Stream + public sealed class BZip2Stream : Stream { private readonly Stream stream; private bool isDisposed; @@ -82,6 +83,20 @@ namespace SharpCompress.Compressors.BZip2 stream.SetLength(value); } +#if NETSTANDARD2_1 + + public override int Read(Span buffer) + { + return stream.Read(buffer); + } + + public override void Write(ReadOnlySpan buffer) + { + stream.Write(buffer); + } + +#endif + public override void Write(byte[] buffer, int offset, int count) { stream.Write(buffer, offset, count); diff --git a/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs b/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs index 5d32c0ac..788f1ba7 100644 --- a/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs +++ b/src/SharpCompress/Compressors/Deflate/ZlibBaseStream.cs @@ -228,12 +228,12 @@ namespace SharpCompress.Compressors.Deflate if (_wantCompress) { // Emit the GZIP trailer: CRC32 and size mod 2^32 - byte[] intBuf = new byte[4]; + Span intBuf = stackalloc byte[4]; BinaryPrimitives.WriteInt32LittleEndian(intBuf, crc.Crc32Result); - _stream.Write(intBuf, 0, 4); - int c2 = (Int32)(crc.TotalBytesRead & 0x00000000FFFFFFFF); + _stream.Write(intBuf); + int c2 = (int)(crc.TotalBytesRead & 0x00000000FFFFFFFF); BinaryPrimitives.WriteInt32LittleEndian(intBuf, c2); - _stream.Write(intBuf, 0, 4); + _stream.Write(intBuf); } else { diff --git a/src/SharpCompress/Compressors/LZMA/LZipStream.cs b/src/SharpCompress/Compressors/LZMA/LZipStream.cs index 88f85c87..bf2e5265 100644 --- a/src/SharpCompress/Compressors/LZMA/LZipStream.cs +++ b/src/SharpCompress/Compressors/LZMA/LZipStream.cs @@ -117,6 +117,23 @@ namespace SharpCompress.Compressors.LZMA public override void SetLength(long value) => throw new NotImplementedException(); + +#if NETSTANDARD2_1 + + public override int Read(Span buffer) + { + return _stream.Read(buffer); + } + + public override void Write(ReadOnlySpan buffer) + { + _stream.Write(buffer); + + _writeCount += buffer.Length; + } + +#endif + public override void Write(byte[] buffer, int offset, int count) { _stream.Write(buffer, offset, count); diff --git a/src/SharpCompress/Crypto/Crc32Stream.cs b/src/SharpCompress/Crypto/Crc32Stream.cs index 2243cec3..c9e26346 100644 --- a/src/SharpCompress/Crypto/Crc32Stream.cs +++ b/src/SharpCompress/Crypto/Crc32Stream.cs @@ -42,10 +42,20 @@ namespace SharpCompress.Crypto public override void SetLength(long value) => throw new NotSupportedException(); +#if NETSTANDARD2_1 + + public override void Write(ReadOnlySpan buffer) + { + stream.Write(buffer); + + hash = CalculateCrc(table, hash, buffer); + } +#endif + public override void Write(byte[] buffer, int offset, int count) { stream.Write(buffer, offset, count); - hash = CalculateCrc(table, hash, buffer, offset, count); + hash = CalculateCrc(table, hash, buffer.AsSpan(offset, count)); } public override void WriteByte(byte value) @@ -72,9 +82,9 @@ namespace SharpCompress.Crypto return Compute(DefaultPolynomial, seed, buffer); } - public static uint Compute(uint polynomial, uint seed, byte[] buffer) + public static uint Compute(uint polynomial, uint seed, ReadOnlySpan buffer) { - return ~CalculateCrc(InitializeTable(polynomial), seed, buffer, 0, buffer.Length); + return ~CalculateCrc(InitializeTable(polynomial), seed, buffer); } private static uint[] InitializeTable(uint polynomial) @@ -111,11 +121,11 @@ namespace SharpCompress.Crypto return createTable; } - private static uint CalculateCrc(uint[] table, uint crc, byte[] buffer, int offset, int count) + private static uint CalculateCrc(uint[] table, uint crc, ReadOnlySpan buffer) { unchecked { - for (int i = offset, end = offset + count; i < end; i++) + for (int i = 0; i < buffer.Length; i++) { crc = CalculateCrc(table, crc, buffer[i]); } diff --git a/src/SharpCompress/Polyfills/StreamExtensions.cs b/src/SharpCompress/Polyfills/StreamExtensions.cs new file mode 100644 index 00000000..95118885 --- /dev/null +++ b/src/SharpCompress/Polyfills/StreamExtensions.cs @@ -0,0 +1,25 @@ +#if !NETSTANDARD2_1 + +using System.Buffers; + +namespace System.IO +{ + public static class StreamExtensions + { + public static void Write(this Stream stream, ReadOnlySpan buffer) + { + var temp = ArrayPool.Shared.Rent(buffer.Length); + + try + { + stream.Write(temp, 0, buffer.Length); + } + finally + { + ArrayPool.Shared.Return(temp); + } + } + } +} + +#endif \ No newline at end of file diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.cs b/src/SharpCompress/Writers/Zip/ZipWriter.cs index 6b59bf04..74ae7145 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.cs @@ -170,16 +170,16 @@ namespace SharpCompress.Writers.Zip { if (OutputStream.CanSeek && useZip64) { - OutputStream.Write(new byte[] { 45, 0 }, 0, 2); //smallest allowed version for zip64 + OutputStream.Write(stackalloc byte[] { 45, 0 }); //smallest allowed version for zip64 } else { - OutputStream.Write(new byte[] { 20, 0 }, 0, 2); //older version which is more compatible + OutputStream.Write(stackalloc byte[] { 20, 0 }); //older version which is more compatible } } else { - OutputStream.Write(new byte[] { 63, 0 }, 0, 2); //version says we used PPMd or LZMA + OutputStream.Write(stackalloc byte[] { 63, 0 }); //version says we used PPMd or LZMA } HeaderFlags flags = Equals(WriterOptions.ArchiveEncoding.GetEncoding(), Encoding.UTF8) ? HeaderFlags.Efs : 0; if (!OutputStream.CanSeek) @@ -200,7 +200,7 @@ namespace SharpCompress.Writers.Zip OutputStream.Write(intBuf, 0, 4); // zipping date and time - OutputStream.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 12); + OutputStream.Write(stackalloc byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); // unused CRC, un/compressed size, updated later BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedFilename.Length); @@ -250,7 +250,7 @@ namespace SharpCompress.Writers.Zip var recordlen = 2 + 2 + 4 + 4 + 8 + 8 + 8 + 8; // Write zip64 end of central directory record - OutputStream.Write(new byte[] { 80, 75, 6, 6 }, 0, 4); + OutputStream.Write(stackalloc byte[] { 80, 75, 6, 6 }); BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)recordlen); OutputStream.Write(intBuf, 0, 8); // Size of zip64 end of central directory record @@ -273,7 +273,7 @@ namespace SharpCompress.Writers.Zip OutputStream.Write(intBuf, 0, 8); // Disk offset // Write zip64 end of central directory locator - OutputStream.Write(new byte[] { 80, 75, 6, 7 }, 0, 4); + OutputStream.Write(stackalloc byte[] { 80, 75, 6, 7 }); BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0); OutputStream.Write(intBuf, 0, 4); // Entry disk @@ -287,7 +287,7 @@ namespace SharpCompress.Writers.Zip } // Write normal end of central directory record - OutputStream.Write(new byte[] { 80, 75, 5, 6, 0, 0, 0, 0 }, 0, 8); + OutputStream.Write(stackalloc byte[] { 80, 75, 5, 6, 0, 0, 0, 0 }); BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)entries.Count); OutputStream.Write(intBuf, 0, 2); OutputStream.Write(intBuf, 0, 2);