Skip to content

Commit 6489e48

Browse files
committed
more
1 parent 7391735 commit 6489e48

File tree

2 files changed

+73
-36
lines changed

2 files changed

+73
-36
lines changed

src/Renci.SshNet/Common/SshData.cs

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.IO;
34
using System.Text;
45

56
namespace Renci.SshNet.Common
@@ -143,24 +144,10 @@ protected byte[] ReadBytes()
143144
/// </summary>
144145
/// <param name="length">Number of bytes to read.</param>
145146
/// <returns>An array of bytes that was read from the internal buffer.</returns>
146-
/// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is greater than the internal buffer size.</exception>
147+
/// <exception cref="EndOfStreamException"><paramref name="length"/> is greater than the internal buffer size.</exception>
147148
protected byte[] ReadBytes(int length)
148149
{
149-
/*
150-
* Note that this also prevents allocating non-relevant lengths, such as if length is greater than _data.Count but less than int.MaxValue.
151-
* For the nerds, the condition translates to: if (length > data.Count && length < int.MaxValue)
152-
* Which probably would cause all sorts of exception, most notably OutOfMemoryException.
153-
*/
154-
155-
var data = new byte[length];
156-
var bytesRead = _stream.Read(data, 0, length);
157-
158-
if (bytesRead < length)
159-
{
160-
throw new ArgumentOutOfRangeException(nameof(length));
161-
}
162-
163-
return data;
150+
return _stream.ReadBytes(length);
164151
}
165152

166153
/// <summary>
@@ -197,7 +184,7 @@ protected bool ReadBoolean()
197184
/// </returns>
198185
protected ushort ReadUInt16()
199186
{
200-
return Pack.BigEndianToUInt16(ReadBytes(2));
187+
return _stream.ReadUInt16();
201188
}
202189

203190
/// <summary>
@@ -208,7 +195,7 @@ protected ushort ReadUInt16()
208195
/// </returns>
209196
protected uint ReadUInt32()
210197
{
211-
return Pack.BigEndianToUInt32(ReadBytes(4));
198+
return _stream.ReadUInt32();
212199
}
213200

214201
/// <summary>
@@ -219,7 +206,7 @@ protected uint ReadUInt32()
219206
/// </returns>
220207
protected ulong ReadUInt64()
221208
{
222-
return Pack.BigEndianToUInt64(ReadBytes(8));
209+
return _stream.ReadUInt64();
223210
}
224211

225212
/// <summary>

src/Renci.SshNet/Common/SshDataStream.cs

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,24 @@ public BigInteger ReadBigInt()
195195
return new BigInteger(data.Reverse());
196196
}
197197

198+
/// <summary>
199+
/// Reads the next <see cref="ushort"/> data type from the SSH data stream.
200+
/// </summary>
201+
/// <returns>
202+
/// The <see cref="ushort"/> read from the SSH data stream.
203+
/// </returns>
204+
public ushort ReadUInt16()
205+
{
206+
#if NET6_0_OR_GREATER
207+
Span<byte> bytes = stackalloc byte[2];
208+
ReadExactly(bytes);
209+
return BinaryPrimitives.ReadUInt16BigEndian(bytes);
210+
#else
211+
var data = ReadBytes(2);
212+
return Pack.BigEndianToUInt16(data);
213+
#endif
214+
}
215+
198216
/// <summary>
199217
/// Reads the next <see cref="uint"/> data type from the SSH data stream.
200218
/// </summary>
@@ -205,7 +223,7 @@ public uint ReadUInt32()
205223
{
206224
#if NET6_0_OR_GREATER
207225
Span<byte> bytes = stackalloc byte[4];
208-
ReadBytes(bytes);
226+
ReadExactly(bytes);
209227
return BinaryPrimitives.ReadUInt32BigEndian(bytes);
210228
#else
211229
var data = ReadBytes(4);
@@ -223,7 +241,7 @@ public ulong ReadUInt64()
223241
{
224242
#if NET6_0_OR_GREATER
225243
Span<byte> bytes = stackalloc byte[8];
226-
ReadBytes(bytes);
244+
ReadExactly(bytes);
227245
return BinaryPrimitives.ReadUInt64BigEndian(bytes);
228246
#else
229247
var data = ReadBytes(8);
@@ -278,33 +296,65 @@ public override byte[] ToArray()
278296
/// <returns>
279297
/// An array of bytes that was read from the internal buffer.
280298
/// </returns>
281-
/// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is greater than the internal buffer size.</exception>
282-
private byte[] ReadBytes(int length)
299+
/// <exception cref="EndOfStreamException"><paramref name="length"/> is greater than the internal buffer size.</exception>
300+
internal byte[] ReadBytes(int length)
283301
{
284302
var data = new byte[length];
285-
var bytesRead = Read(data, 0, length);
286303

287-
if (bytesRead < length)
288-
{
289-
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));
290-
}
304+
ReadExactly(data);
291305

292306
return data;
293307
}
294308

295-
#if NET6_0_OR_GREATER
309+
#if NET6_0
296310
/// <summary>
297-
/// Fills the specified span with bytes from the internal buffer.
311+
/// Reads bytes from the current stream and advances the position within the stream until the <paramref name="buffer"/> is filled.
298312
/// </summary>
299-
/// <param name="destination">The span to fill.</param>
300-
/// <exception cref="ArgumentException">The Length of <paramref name="destination"/> is greater than the actual number of bytes read.</exception>
301-
private void ReadBytes(Span<byte> destination)
313+
/// <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>
314+
/// <exception cref="EndOfStreamException">
315+
/// The end of the stream is reached before filling the <paramref name="buffer"/>.
316+
/// </exception>
317+
/// <remarks>
318+
/// When <paramref name="buffer"/> is empty, this read operation will be completed without waiting for available data in the stream.
319+
/// </remarks>
320+
private void ReadExactly(Span<byte> buffer)
302321
{
303-
var bytesRead = Read(destination);
322+
var totalRead = 0;
323+
while (totalRead < buffer.Length)
324+
{
325+
var read = Read(buffer.Slice(totalRead));
326+
if (read == 0)
327+
{
328+
throw new EndOfStreamException();
329+
}
330+
331+
totalRead += read;
332+
}
333+
}
304334

305-
if (bytesRead < destination.Length)
335+
#elif !NET7_0_OR_GREATER
336+
/// <summary>
337+
/// Reads bytes from the current stream and advances the position within the stream until the <paramref name="buffer"/> is filled.
338+
/// </summary>
339+
/// <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>
340+
/// <exception cref="EndOfStreamException">
341+
/// The end of the stream is reached before filling the <paramref name="buffer"/>.
342+
/// </exception>
343+
/// <remarks>
344+
/// When <paramref name="buffer"/> is empty, this read operation will be completed without waiting for available data in the stream.
345+
/// </remarks>
346+
private void ReadExactly(byte[] buffer)
347+
{
348+
var totalRead = 0;
349+
while (totalRead < buffer.Length)
306350
{
307-
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));
351+
var read = Read(buffer, totalRead, buffer.Length - totalRead);
352+
if (read == 0)
353+
{
354+
throw new EndOfStreamException();
355+
}
356+
357+
totalRead += read;
308358
}
309359
}
310360
#endif

0 commit comments

Comments
 (0)