Skip to content

Commit debbb05

Browse files
committed
Fix StreamExtensions.Read<T> for buffered streams
1 parent 6fff80d commit debbb05

File tree

1 file changed

+25
-7
lines changed

1 file changed

+25
-7
lines changed

src/CommunityToolkit.HighPerformance/Extensions/StreamExtensions.cs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -207,27 +207,45 @@ public static unsafe T Read<T>(this Stream stream)
207207
{
208208
#if NETSTANDARD2_1_OR_GREATER
209209
T result = default;
210-
int length = sizeof(T);
210+
int bytesOffset = 0;
211211

212-
unsafe
212+
// As per Stream.Read's documentation:
213+
// "The total number of bytes read into the buffer. This can be less than the number of bytes allocated in the
214+
// buffer if that many bytes are not currently available, or zero (0) if the end of the stream has been reached."
215+
// Because of this, we have to loop until all requires bytes have been read, and only throw if the return is 0.
216+
do
213217
{
214-
if (stream.Read(new Span<byte>(&result, length)) != length)
218+
int bytesRead = stream.Read(new Span<byte>((byte*)&result + bytesOffset, sizeof(T) - bytesOffset));
219+
220+
// A return value of 0 indicates that the end of the stream has been reached
221+
if (bytesRead == 0)
215222
{
216223
ThrowInvalidOperationExceptionForEndOfStream();
217224
}
225+
226+
bytesOffset += bytesRead;
218227
}
228+
while (bytesOffset < sizeof(T));
219229

220230
return result;
221231
#else
222-
int length = sizeof(T);
223-
byte[] buffer = ArrayPool<byte>.Shared.Rent(length);
232+
int bytesOffset = 0;
233+
byte[] buffer = ArrayPool<byte>.Shared.Rent(sizeof(T));
224234

225235
try
226236
{
227-
if (stream.Read(buffer, 0, length) != length)
237+
do
228238
{
229-
ThrowInvalidOperationExceptionForEndOfStream();
239+
int bytesRead = stream.Read(buffer.AsSpan(bytesOffset, sizeof(T) - bytesOffset));
240+
241+
if (bytesRead == 0)
242+
{
243+
ThrowInvalidOperationExceptionForEndOfStream();
244+
}
245+
246+
bytesOffset += bytesRead;
230247
}
248+
while (bytesOffset < sizeof(T));
231249

232250
return Unsafe.ReadUnaligned<T>(ref buffer[0]);
233251
}

0 commit comments

Comments
 (0)