diff --git a/LibGit/Extensions/StreamExtensions.cs b/LibGit/Extensions/StreamExtensions.cs
index 41e4b4f..90bd35a 100644
--- a/LibGit/Extensions/StreamExtensions.cs
+++ b/LibGit/Extensions/StreamExtensions.cs
@@ -1,4 +1,5 @@
using System.IO.Compression;
+using System.Runtime.InteropServices;
namespace LibGit.Extensions;
@@ -53,18 +54,25 @@ public static class StreamExtensions
{
if (!stream.CanRead)
throw new InvalidOperationException("Can't read a non-readable stream");
- if (!stream.CanSeek)
- throw new InvalidOperationException("Can't read a non-seekable stream");
- for (long i = 0; i < count; i++)
+ var buffer = new byte[count];
+ var readCount = stream.Read(buffer, 0, (int)count);
+ for (int i = 0; i < readCount; i++)
{
- int read = stream.ReadByte();
- if (read == -1)
- yield break;
- yield return (byte)read;
+ yield return buffer[i];
}
}
+ public static byte[] ReadBlock(this Stream stream, int count)
+ {
+ if (!stream.CanRead)
+ throw new InvalidOperationException("Can't read a non-readable stream");
+
+ Span<byte> buffer = stackalloc byte[count];
+ stream.ReadExactly(buffer);
+ return buffer.ToArray();
+ }
+
public static bool StartsWith(this Stream stream, IEnumerable<byte> sequence)
{
if (!stream.CanRead)
@@ -172,13 +180,25 @@ public static class StreamExtensions
if (!stream.CanRead)
throw new InvalidOperationException("Can't read a non-readable stream");
- var bytes = stream.ReadBytes(4).ToArray();
+ Span<byte> b = stackalloc byte[4];
+ stream.ReadExactly(b);
+ return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
+ }
- if (BitConverter.IsLittleEndian)
- Array.Reverse(bytes);
+ public static int[] MultiReadInt32BE(this Stream stream, int count)
+ {
+ if (!stream.CanRead)
+ throw new InvalidOperationException("Can't read a non-readable stream");
- // Console.WriteLine("ReadInt32BE: " + bytes.AsHexString() + " => " + BitConverter.ToInt32(bytes));
- return BitConverter.ToInt32(bytes);
+ Span<byte> b = stackalloc byte[4 * count];
+ stream.ReadExactly(b);
+ int[] results = new int[count];
+ for (int i = 0; i < count; i++)
+ {
+ results[i] = (b[i * 4 + 0] << 24) | (b[i * 4 + 1] << 16) | (b[i * 4 + 2] << 8) | b[i * 4 + 3];
+ }
+
+ return results;
}
public static uint ReadUInt32BE(this Stream stream)
@@ -186,13 +206,25 @@ public static class StreamExtensions
if (!stream.CanRead)
throw new InvalidOperationException("Can't read a non-readable stream");
- var bytes = stream.ReadBytes(4).ToArray();
+ Span<byte> b = stackalloc byte[4];
+ stream.ReadExactly(b);
+ return (uint)((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
+ }
+
+ public static uint[] MultiReadUInt32BE(this Stream stream, int count)
+ {
+ if (!stream.CanRead)
+ throw new InvalidOperationException("Can't read a non-readable stream");
- if (BitConverter.IsLittleEndian)
- Array.Reverse(bytes);
+ Span<byte> b = count >= 32767 ? new byte[4 * count] : stackalloc byte[4 * count];
+ stream.ReadExactly(b);
+ uint[] results = new uint[count];
+ for (int i = 0; i < count; i++)
+ {
+ results[i] = (uint)((b[i * 4 + 0] << 24) | (b[i * 4 + 1] << 16) | (b[i * 4 + 2] << 8) | b[i * 4 + 3]);
+ }
- // Console.WriteLine("ReadUInt32BE: " + bytes.AsHexString() + " => " + BitConverter.ToUInt32(bytes));
- return BitConverter.ToUInt32(bytes);
+ return results;
}
public static ulong ReadUInt64BE(this Stream stream)
@@ -200,13 +232,38 @@ public static class StreamExtensions
if (!stream.CanRead)
throw new InvalidOperationException("Can't read a non-readable stream");
- var bytes = stream.ReadBytes(8).ToArray();
+ Span<byte> b = stackalloc byte[8];
+ stream.ReadExactly(b);
+ return ((ulong)b[0] << 56) | ((ulong)b[1] << 48) | ((ulong)b[2] << 40) | ((ulong)b[3] << 32) |
+ ((ulong)b[4] << 24) | ((ulong)b[5] << 16) | ((ulong)b[6] << 8) | b[7];
+ }
- if (BitConverter.IsLittleEndian)
- Array.Reverse(bytes);
+ public static ulong[] MultiReadUInt64BE(this Stream stream, int count)
+ {
+ if (!stream.CanRead)
+ throw new InvalidOperationException("Can't read a non-readable stream");
+
+ Span<byte> b = count >= 16384 ? new byte[8 * count] : stackalloc byte[8 * count];
+ stream.ReadExactly(b);
+ ulong[] results = new ulong[count];
+ for (int i = 0; i < count; i++)
+ {
+ results[i] = ((ulong)b[i * 8 + 0] << 56) | ((ulong)b[i * 8 + 1] << 48) | ((ulong)b[i * 8 + 2] << 40) | ((ulong)b[i * 8 + 3] << 32) |
+ ((ulong)b[i * 8 + 4] << 24) | ((ulong)b[i * 8 + 5] << 16) | ((ulong)b[i * 8 + 6] << 8) | b[i * 8 + 7];
+ }
+
+ return results;
+ }
+
+ public static T[] MultiReadInlineArray<T>(this Stream stream, int count) where T : unmanaged
+ {
+ if (!stream.CanRead)
+ throw new InvalidOperationException("Can't read a non-readable stream");
- // Console.WriteLine("ReadUInt64BE: " + bytes.AsHexString() + " => " + BitConverter.ToUInt64(bytes));
- return BitConverter.ToUInt64(bytes);
+ Span<T> buffer = count >= 8192 ? new T[count] : stackalloc T[count];
+ Span<byte> byteBuffer = MemoryMarshal.AsBytes(buffer);
+ stream.ReadExactly(byteBuffer);
+ return buffer.ToArray();
}
//read variable length number
|