Skip to content

Commit

Permalink
more
Browse files Browse the repository at this point in the history
  • Loading branch information
Rob-Hague committed Jun 10, 2023
1 parent 7391735 commit 6489e48
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 36 deletions.
25 changes: 6 additions & 19 deletions src/Renci.SshNet/Common/SshData.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Renci.SshNet.Common
Expand Down Expand Up @@ -143,24 +144,10 @@ protected byte[] ReadBytes()
/// </summary>
/// <param name="length">Number of bytes to read.</param>
/// <returns>An array of bytes that was read from the internal buffer.</returns>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is greater than the internal buffer size.</exception>
/// <exception cref="EndOfStreamException"><paramref name="length"/> is greater than the internal buffer size.</exception>
protected byte[] ReadBytes(int length)
{
/*
* Note that this also prevents allocating non-relevant lengths, such as if length is greater than _data.Count but less than int.MaxValue.
* For the nerds, the condition translates to: if (length > data.Count && length < int.MaxValue)
* Which probably would cause all sorts of exception, most notably OutOfMemoryException.
*/

var data = new byte[length];
var bytesRead = _stream.Read(data, 0, length);

if (bytesRead < length)
{
throw new ArgumentOutOfRangeException(nameof(length));
}

return data;
return _stream.ReadBytes(length);
}

/// <summary>
Expand Down Expand Up @@ -197,7 +184,7 @@ protected bool ReadBoolean()
/// </returns>
protected ushort ReadUInt16()
{
return Pack.BigEndianToUInt16(ReadBytes(2));
return _stream.ReadUInt16();
}

/// <summary>
Expand All @@ -208,7 +195,7 @@ protected ushort ReadUInt16()
/// </returns>
protected uint ReadUInt32()
{
return Pack.BigEndianToUInt32(ReadBytes(4));
return _stream.ReadUInt32();
}

/// <summary>
Expand All @@ -219,7 +206,7 @@ protected uint ReadUInt32()
/// </returns>
protected ulong ReadUInt64()
{
return Pack.BigEndianToUInt64(ReadBytes(8));
return _stream.ReadUInt64();
}

/// <summary>
Expand Down
84 changes: 67 additions & 17 deletions src/Renci.SshNet/Common/SshDataStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,24 @@ public BigInteger ReadBigInt()
return new BigInteger(data.Reverse());
}

/// <summary>
/// Reads the next <see cref="ushort"/> data type from the SSH data stream.
/// </summary>
/// <returns>
/// The <see cref="ushort"/> read from the SSH data stream.
/// </returns>
public ushort ReadUInt16()
{
#if NET6_0_OR_GREATER
Span<byte> bytes = stackalloc byte[2];
ReadExactly(bytes);
return BinaryPrimitives.ReadUInt16BigEndian(bytes);
#else
var data = ReadBytes(2);
return Pack.BigEndianToUInt16(data);
#endif
}

/// <summary>
/// Reads the next <see cref="uint"/> data type from the SSH data stream.
/// </summary>
Expand All @@ -205,7 +223,7 @@ public uint ReadUInt32()
{
#if NET6_0_OR_GREATER
Span<byte> bytes = stackalloc byte[4];
ReadBytes(bytes);
ReadExactly(bytes);
return BinaryPrimitives.ReadUInt32BigEndian(bytes);
#else
var data = ReadBytes(4);
Expand All @@ -223,7 +241,7 @@ public ulong ReadUInt64()
{
#if NET6_0_OR_GREATER
Span<byte> bytes = stackalloc byte[8];
ReadBytes(bytes);
ReadExactly(bytes);
return BinaryPrimitives.ReadUInt64BigEndian(bytes);
#else
var data = ReadBytes(8);
Expand Down Expand Up @@ -278,33 +296,65 @@ public override byte[] ToArray()
/// <returns>
/// An array of bytes that was read from the internal buffer.
/// </returns>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is greater than the internal buffer size.</exception>
private byte[] ReadBytes(int length)
/// <exception cref="EndOfStreamException"><paramref name="length"/> is greater than the internal buffer size.</exception>
internal byte[] ReadBytes(int length)
{
var data = new byte[length];
var bytesRead = Read(data, 0, length);

if (bytesRead < length)
{
throw new ArgumentOutOfRangeException(nameof(length), string.Format(CultureInfo.InvariantCulture, "The requested length ({0}) is greater than the actual number of bytes read ({1}).", length, bytesRead));
}
ReadExactly(data);

return data;
}

#if NET6_0_OR_GREATER
#if NET6_0
/// <summary>
/// Fills the specified span with bytes from the internal buffer.
/// Reads bytes from the current stream and advances the position within the stream until the <paramref name="buffer"/> is filled.
/// </summary>
/// <param name="destination">The span to fill.</param>
/// <exception cref="ArgumentException">The Length of <paramref name="destination"/> is greater than the actual number of bytes read.</exception>
private void ReadBytes(Span<byte> destination)
/// <param name="buffer">A region of memory. When this method returns, the contents of this region are replaced by the bytes read from the current stream.</param>
/// <exception cref="EndOfStreamException">
/// The end of the stream is reached before filling the <paramref name="buffer"/>.
/// </exception>
/// <remarks>
/// When <paramref name="buffer"/> is empty, this read operation will be completed without waiting for available data in the stream.
/// </remarks>
private void ReadExactly(Span<byte> buffer)
{
var bytesRead = Read(destination);
var totalRead = 0;
while (totalRead < buffer.Length)
{
var read = Read(buffer.Slice(totalRead));
if (read == 0)
{
throw new EndOfStreamException();
}

totalRead += read;
}
}

if (bytesRead < destination.Length)
#elif !NET7_0_OR_GREATER
/// <summary>
/// Reads bytes from the current stream and advances the position within the stream until the <paramref name="buffer"/> is filled.
/// </summary>
/// <param name="buffer">A region of memory. When this method returns, the contents of this region are replaced by the bytes read from the current stream.</param>
/// <exception cref="EndOfStreamException">
/// The end of the stream is reached before filling the <paramref name="buffer"/>.
/// </exception>
/// <remarks>
/// When <paramref name="buffer"/> is empty, this read operation will be completed without waiting for available data in the stream.
/// </remarks>
private void ReadExactly(byte[] buffer)
{
var totalRead = 0;
while (totalRead < buffer.Length)
{
throw new ArgumentException(nameof(destination), string.Format(CultureInfo.InvariantCulture, "The requested length ({0}) is greater than the actual number of bytes read ({1}).", destination.Length, bytesRead));
var read = Read(buffer, totalRead, buffer.Length - totalRead);
if (read == 0)
{
throw new EndOfStreamException();
}

totalRead += read;
}
}
#endif
Expand Down

0 comments on commit 6489e48

Please sign in to comment.