From bae16c0471bb67b39efd1dc9ed0d7bfc84e78c27 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 27 Aug 2024 17:03:16 +0200 Subject: [PATCH] Add Stream.ReadBytes extension --- .../Extensions/StreamExtensions.cs | 36 +++++++ .../Extensions/StreamTests.cs | 93 +++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/Aardvark.Base/Extensions/StreamExtensions.cs create mode 100644 src/Tests/Aardvark.Base.Tests/Extensions/StreamTests.cs diff --git a/src/Aardvark.Base/Extensions/StreamExtensions.cs b/src/Aardvark.Base/Extensions/StreamExtensions.cs new file mode 100644 index 00000000..ed6e701c --- /dev/null +++ b/src/Aardvark.Base/Extensions/StreamExtensions.cs @@ -0,0 +1,36 @@ +using System.IO; + +namespace Aardvark.Base +{ + public static class StreamExtensions + { + /// + /// Reads number of bytes from the current stream and advances the position within the stream. + /// + /// The stream to read from. + /// The buffer to read into. + /// The byte offset in at which to begin storing the data read from the current stream. + /// The number of bytes to be read from the current stream. Defaults to the buffer length if negative. + /// + public static void ReadBytes(this Stream stream, byte[] buffer, int offset = 0, int count = -1) + { + if (count < 0) count = buffer.Length; +#if NET8_0_OR_GREATER + stream.ReadExactly(buffer, offset, count); +#else + int totalRead = 0; + + while (totalRead < count) + { + int read = stream.Read(buffer, offset + totalRead, count - totalRead); + if (read == 0) + { + throw new EndOfStreamException(); + } + + totalRead += read; + } +#endif + } + } +} diff --git a/src/Tests/Aardvark.Base.Tests/Extensions/StreamTests.cs b/src/Tests/Aardvark.Base.Tests/Extensions/StreamTests.cs new file mode 100644 index 00000000..7fd70c6c --- /dev/null +++ b/src/Tests/Aardvark.Base.Tests/Extensions/StreamTests.cs @@ -0,0 +1,93 @@ +using NUnit.Framework; +using System; +using System.Reflection; +using System.IO; +using Aardvark.Base; +using System.Linq; + +namespace Aardvark.Tests.Extensions +{ + internal class TestStream(Stream inner) : Stream + { + private bool isDiposed = false; + private readonly RandomSystem rnd = new RandomSystem(); + + public TestStream(byte[] data) : this(new MemoryStream(data)) + { } + + public override bool CanRead => inner.CanRead; + + public override bool CanSeek => inner.CanSeek; + + public override bool CanWrite => inner.CanWrite; + + public override long Length => inner.Length; + + public override long Position + { + get => inner.Position; + set => inner.Position = value; + } + + public override void Flush() => inner.Flush(); + + public override long Seek(long offset, SeekOrigin origin) => inner.Seek(offset, origin); + + public override void SetLength(long value) => inner.SetLength(value); + + public override int Read(byte[] buffer, int offset, int count) + { + if (count > 1) + { + count = 1 + rnd.UniformInt(count - 1); + } + + return inner.Read(buffer, offset, count); + } + + public override void Write(byte[] buffer, int offset, int count) + { + inner.Write(buffer, offset, count); + } + + protected override void Dispose(bool disposing) + { + if (!isDiposed) inner.Dispose(); + isDiposed = true; + } + } + + static class StreamTests + { + [Test] + public static void ReadBytes([Values(false, true)] bool netStandard20) + { + var rnd = new RandomSystem(); + var data = new byte[1234]; + for (int i = 0; i < data.Length; i++) data[i] = (byte)rnd.UniformInt(); + + using TestStream s = new TestStream(data); + var result = new byte[57]; + var offset = 3; + var count = result.Length - offset; + + if (netStandard20) + { + // We want to test the netstandard2.0 implementation, is there an easier way? + var asm = Assembly.LoadFile(Path.GetFullPath(Path.Combine("..", "netstandard2.0", "Aardvark.Base.dll"))); + var ext = asm.GetType($"Aardvark.Base.{nameof(StreamExtensions)}"); + Type[] parameters = [typeof(Stream), typeof(byte[]), typeof(int), typeof(int)]; + var mi = ext.GetMethod(nameof(StreamExtensions.ReadBytes), parameters); + + mi.Invoke(null, [s, result, offset, count]); + } + else + { + s.ReadBytes(result, offset, count); + } + + for (int i = 0; i < count; i++) + Assert.AreEqual(data[i], result[i + offset]); + } + } +}