diff --git a/Core/InteropServices/NativeMemoryStream.cs b/Core/InteropServices/NativeMemoryStream.cs
index a4f45959a..fb331aa6d 100644
--- a/Core/InteropServices/NativeMemoryStream.cs
+++ b/Core/InteropServices/NativeMemoryStream.cs
@@ -3,6 +3,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
+using System.Runtime.CompilerServices;
namespace Vanara.InteropServices;
@@ -115,6 +116,7 @@ public override long Position
/// Ensures the allocated buffer is large enough for the supplied capacity.
/// The new capacity.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void EnsureCapacity(long value)
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value));
@@ -169,7 +171,7 @@ public override int Read(byte[] buffer, int offset, int count)
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset));
ThrowIfDisposed();
if (!CanRead) throw new NotSupportedException();
- if (Position + count > Capacity) throw new ArgumentOutOfRangeException(nameof(count));
+ count = (int)Math.Min(count, Capacity - Position);
if (count > 0)
{
Marshal.Copy(PositionPtr, buffer, offset, count);
@@ -178,6 +180,19 @@ public override int Read(byte[] buffer, int offset, int count)
return count;
}
+ ///
+ /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
+ ///
+ ///
+ /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values replaced by the bytes read
+ /// from the current source.
+ ///
+ ///
+ /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not
+ /// currently available, or zero (0) if the end of the stream has been reached.
+ ///
+ public virtual int Read(byte[] buffer) => Read(buffer, 0, buffer.Length);
+
///
/// Reads a blittable type from the current stream and advances the position within the stream by the number of bytes read.
///
@@ -186,6 +201,7 @@ public override int Read(byte[] buffer, int offset, int count)
/// An object of type .
/// Type to be read must be blittable. - T
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T? Read(CharSet charSet = CharSet.Auto) => (T?)Read(typeof(T), charSet);
///
@@ -332,9 +348,7 @@ public override void SetLength(long value)
///
/// An array of bytes. This method copies bytes from to the current stream.
///
- ///
- /// The zero-based byte offset in at which to begin copying bytes to the current stream.
- ///
+ /// The zero-based byte offset in at which to begin copying bytes to the current stream.
/// The number of bytes to be written to the current stream.
/// buffer
///
@@ -353,9 +367,16 @@ public override void Write(byte[] buffer, int offset, int count)
length += count;
}
+ ///
+ /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
+ ///
+ /// An array of bytes. This method copies all bytes from to the current stream.
+ public virtual void Write(byte[] buffer) => Write(buffer, 0, buffer.Length);
+
/// Writes the specified value into the stream.
/// The type of the value.
/// The value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Write(in T value) where T : struct => WriteObject(value);
/// Writes the specified string into the stream.
@@ -376,6 +397,7 @@ public void Write(string value, CharSet charSetOverride)
/// Write values as a referenced array.
public void Write(IEnumerable? items, bool byRef = false)
{
+ if (items is byte[] b && byRef == false) { Write(b, 0, b.Length); return; }
if (access == FileAccess.Read) throw new NotSupportedException();
if (items == null) return;
ResetIfFlushed();
@@ -455,6 +477,7 @@ public virtual void WriteObject(object? value)
/// or flushed.
///
/// The value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteReference(T value) where T : unmanaged => WriteReferenceObject(value);
///
@@ -462,6 +485,7 @@ public virtual void WriteObject(object? value)
/// or flushed.
///
/// The value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteReference(T? value) where T : unmanaged => WriteReferenceObject(value.HasValue ? value.Value : null);
///
@@ -469,6 +493,7 @@ public virtual void WriteObject(object? value)
/// or flushed.
///
/// The string value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteReference(string? value) => WriteReferenceObject(value);
/// Writes the specified value into the stream. This function should fail if the object cannot be blitted.
@@ -500,9 +525,11 @@ protected override void Dispose(bool disposing)
/// The object to check.
/// The character set.
/// The size, in bytes, of the object.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
protected virtual int GetSize(object? obj, CharSet charSet = CharSet.None) =>
InteropExtensions.SizeOf(obj, charSet);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetRefSize() => references.Sum(e => GetSize(e.Value, CharSet));
private void ResetIfFlushed()
@@ -513,11 +540,13 @@ private void ResetIfFlushed()
preflushPos = 0;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ThrowIfDisposed()
{
if (IsDisposed) throw new ObjectDisposedException(nameof(NativeMemoryStream));
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private T ThrowIfDisposed(T value) => !IsDisposed ? value : throw new ObjectDisposedException(nameof(NativeMemoryStream));
private class Reference
diff --git a/UnitTests/Core/InteropServices/NativeMemoryStreamTests.cs b/UnitTests/Core/InteropServices/NativeMemoryStreamTests.cs
index e38ca7926..1787c6ffb 100644
--- a/UnitTests/Core/InteropServices/NativeMemoryStreamTests.cs
+++ b/UnitTests/Core/InteropServices/NativeMemoryStreamTests.cs
@@ -123,6 +123,20 @@ public void NativeMemoryStreamTest2()
Assert.That(() => ms.Write(Guid.NewGuid()), Throws.Exception);
}
+ [Test]
+ public void NativeVsNormalTest()
+ {
+ var buffer = new byte[1000];
+ var temp1 = new MemoryStream();
+ var temp2 = new NativeMemoryStream();
+
+ temp1.Write(new byte[1000]);
+ temp2.Write(new byte[1000]);
+
+ Assert.That(temp1.Read(buffer, 0, 100), Is.EqualTo(0)); // Normal for MemoryStream, return value is 0
+ Assert.That(temp2.Read(buffer, 0, 100), Is.EqualTo(0)); // NativeMemoryStream throw ArgumentOutOfRangeException here
+ }
+
[Test]
public void MixedReadWriteTest()
{