From 5cfc608010d8ac65ded7d1fa2f086a2288b8486d Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sun, 21 Feb 2021 13:21:33 +0000 Subject: [PATCH] More fixes? --- .../Common/Zip/StreamingZipHeaderFactory.cs | 8 +- src/SharpCompress/Utility.cs | 73 ++++++++++++++----- tests/SharpCompress.Test/TestBase.cs | 2 +- 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs index 339ac23b..7d242b0f 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs @@ -37,8 +37,12 @@ namespace SharpCompress.Common.Zip } } _lastEntryHeader = null; - uint headerBytes = await rewindableStream.ReadUInt32(cancellationToken); - header = await ReadHeader(headerBytes, rewindableStream, cancellationToken); + var headerBytes = await rewindableStream.ReadUInt32OrNull(cancellationToken); + if (headerBytes is null) + { + yield break; + } + header = await ReadHeader(headerBytes.Value, rewindableStream, cancellationToken); if (header is null) { yield break; diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index 0f879a3b..282573ec 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; using System.IO; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using SharpCompress.Readers; @@ -18,38 +19,81 @@ namespace SharpCompress await action(item); } } - public static async ValueTask ReadPrimitive(this Stream stream, int bytes, Func, T> func, CancellationToken cancellationToken) + + private static async ValueTask WritePrimitive(this Stream stream, Action> func, CancellationToken cancellationToken) + where T : struct { + var bytes = Marshal.SizeOf(); + using var buffer = MemoryPool.Shared.Rent(bytes); + var memory = buffer.Memory.Slice(0, bytes); + func(memory); + await stream.WriteAsync(memory, cancellationToken); + } + + public static ValueTask WriteByteAsync(this Stream stream, byte val, CancellationToken cancellationToken = default) + { + return stream.WritePrimitive( x => x.Span[0] = val, cancellationToken); + } + + public static async ValueTask WriteBytes(this Stream stream, params byte[] val) + { + using var buffer = MemoryPool.Shared.Rent(val.Length); + var memory = buffer.Memory.Slice(0, val.Length); + val.CopyTo(memory); + await stream.WriteAsync(memory); + } + + public static ValueTask WriteUInt16(this Stream stream, ushort val, CancellationToken cancellationToken =default) + { + return stream.WritePrimitive( x => BinaryPrimitives.WriteUInt16LittleEndian(x.Span, val), cancellationToken); + } + public static ValueTask WriteUInt32(this Stream stream, uint val, CancellationToken cancellationToken= default) + { + return stream.WritePrimitive( x => BinaryPrimitives.WriteUInt32LittleEndian(x.Span, val), cancellationToken); + } + public static ValueTask WriteUInt64(this Stream stream, ulong val, CancellationToken cancellationToken= default) + { + return stream.WritePrimitive( x => BinaryPrimitives.WriteUInt64LittleEndian(x.Span, val), cancellationToken); + } + + private static async ValueTask ReadPrimitive(this Stream stream, Func, T> func, CancellationToken cancellationToken) + where T : struct + { + var bytes = Marshal.SizeOf(); using var buffer = MemoryPool.Shared.Rent(bytes); var memory = buffer.Memory.Slice(0, bytes); var n = await stream.ReadAsync(memory, cancellationToken); if (n != memory.Length) { - throw new InvalidOperationException("Unexpected length"); + return null; } return func(memory); } - public static ValueTask ReadByteAsync(this Stream stream, CancellationToken cancellationToken) + public static async ValueTask ReadByteAsync(this Stream stream, CancellationToken cancellationToken) { - return stream.ReadPrimitive(1, x => x.Span[0], cancellationToken); + return await stream.ReadPrimitive(x => x.Span[0], cancellationToken) ?? default; } - public static ValueTask ReadUInt16(this Stream stream, CancellationToken cancellationToken) + public static async ValueTask ReadUInt16(this Stream stream, CancellationToken cancellationToken) { - return stream.ReadPrimitive(2, x => BinaryPrimitives.ReadUInt16LittleEndian(x.Span), cancellationToken); + return await stream.ReadPrimitive( x => BinaryPrimitives.ReadUInt16LittleEndian(x.Span), cancellationToken)?? default; } - public static ValueTask ReadUInt32(this Stream stream, CancellationToken cancellationToken) + public static async ValueTask ReadUInt32(this Stream stream, CancellationToken cancellationToken) { - return stream.ReadPrimitive(4, x => BinaryPrimitives.ReadUInt32LittleEndian(x.Span), cancellationToken); + return await stream.ReadPrimitive( x => BinaryPrimitives.ReadUInt32LittleEndian(x.Span), cancellationToken)?? default; } - public static ValueTask ReadInt32(this Stream stream, CancellationToken cancellationToken) + public static ValueTask ReadUInt32OrNull(this Stream stream, CancellationToken cancellationToken) { - return stream.ReadPrimitive(4, x => BinaryPrimitives.ReadInt32LittleEndian(x.Span), cancellationToken); + return stream.ReadPrimitive(x => BinaryPrimitives.ReadUInt32LittleEndian(x.Span), cancellationToken); + } + public static async ValueTask ReadInt32(this Stream stream, CancellationToken cancellationToken) + { + return await stream.ReadPrimitive( x => BinaryPrimitives.ReadInt32LittleEndian(x.Span), cancellationToken)?? default; } - public static ValueTask ReadUInt64(this Stream stream, CancellationToken cancellationToken) + public static async ValueTask ReadUInt64(this Stream stream, CancellationToken cancellationToken) { - return stream.ReadPrimitive(8, x => BinaryPrimitives.ReadUInt64LittleEndian(x.Span), cancellationToken); + return await stream.ReadPrimitive( x => BinaryPrimitives.ReadUInt64LittleEndian(x.Span), cancellationToken)?? default; } public static async ValueTask ReadBytes(this Stream stream, int bytes, CancellationToken cancellationToken) @@ -341,11 +385,6 @@ namespace SharpCompress return total; } - public static async ValueTask WriteByte(this Stream stream, byte b, CancellationToken cancellationToken = default) - { - await stream.WriteAsync(new ReadOnlyMemory(new[] {b}), cancellationToken); - } - public static long TransferTo(this Stream source, Stream destination) { byte[] array = GetTransferByteArray(); diff --git a/tests/SharpCompress.Test/TestBase.cs b/tests/SharpCompress.Test/TestBase.cs index b77c32f2..bf53e190 100644 --- a/tests/SharpCompress.Test/TestBase.cs +++ b/tests/SharpCompress.Test/TestBase.cs @@ -82,7 +82,7 @@ namespace SharpCompress.Test Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories) .ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length)); - Assert.Equal(extracted.Count, original.Count); + Assert.Equal(original.Count, extracted.Count); foreach (var orig in original) {