Skip to content

Commit

Permalink
Add Stream.ReadBytes extension
Browse files Browse the repository at this point in the history
  • Loading branch information
hyazinthh committed Aug 27, 2024
1 parent 20df0d2 commit bae16c0
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 0 deletions.
36 changes: 36 additions & 0 deletions src/Aardvark.Base/Extensions/StreamExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.IO;

namespace Aardvark.Base
{
public static class StreamExtensions
{
/// <summary>
/// Reads <paramref name="count"/> number of bytes from the current stream and advances the position within the stream.
/// </summary>
/// <param name="stream">The stream to read from.</param>
/// <param name="buffer">The buffer to read into.</param>
/// <param name="offset">The byte offset in <paramref name="buffer"/> at which to begin storing the data read from the current stream.</param>
/// <param name="count">The number of bytes to be read from the current stream. Defaults to the buffer length if negative.</param>
/// <exception cref="EndOfStreamException"></exception>
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
}
}
}
93 changes: 93 additions & 0 deletions src/Tests/Aardvark.Base.Tests/Extensions/StreamTests.cs
Original file line number Diff line number Diff line change
@@ -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]);
}
}
}

0 comments on commit bae16c0

Please sign in to comment.