StreamUtils.cs
1 using Microsoft.IO; 2 using Ryujinx.Common.Memory; 3 using System.IO; 4 using System.Threading; 5 using System.Threading.Tasks; 6 7 namespace Ryujinx.Common.Utilities 8 { 9 public static class StreamUtils 10 { 11 public static byte[] StreamToBytes(Stream input) 12 { 13 using RecyclableMemoryStream output = StreamToRecyclableMemoryStream(input); 14 15 return output.ToArray(); 16 } 17 18 public static MemoryOwner<byte> StreamToRentedMemory(Stream input) 19 { 20 if (input is MemoryStream inputMemoryStream) 21 { 22 return MemoryStreamToRentedMemory(inputMemoryStream); 23 } 24 else if (input.CanSeek) 25 { 26 long bytesExpected = input.Length; 27 28 MemoryOwner<byte> ownedMemory = MemoryOwner<byte>.Rent(checked((int)bytesExpected)); 29 30 var destSpan = ownedMemory.Span; 31 32 int totalBytesRead = 0; 33 34 while (totalBytesRead < bytesExpected) 35 { 36 int bytesRead = input.Read(destSpan[totalBytesRead..]); 37 38 if (bytesRead == 0) 39 { 40 ownedMemory.Dispose(); 41 42 throw new IOException($"Tried reading {bytesExpected} but the stream closed after reading {totalBytesRead}."); 43 } 44 45 totalBytesRead += bytesRead; 46 } 47 48 return ownedMemory; 49 } 50 else 51 { 52 // If input is (non-seekable) then copy twice: first into a RecyclableMemoryStream, then to a rented IMemoryOwner<byte>. 53 using RecyclableMemoryStream output = StreamToRecyclableMemoryStream(input); 54 55 return MemoryStreamToRentedMemory(output); 56 } 57 } 58 59 public static async Task<byte[]> StreamToBytesAsync(Stream input, CancellationToken cancellationToken = default) 60 { 61 using MemoryStream stream = MemoryStreamManager.Shared.GetStream(); 62 63 await input.CopyToAsync(stream, cancellationToken); 64 65 return stream.ToArray(); 66 } 67 68 private static MemoryOwner<byte> MemoryStreamToRentedMemory(MemoryStream input) 69 { 70 input.Position = 0; 71 72 MemoryOwner<byte> ownedMemory = MemoryOwner<byte>.Rent(checked((int)input.Length)); 73 74 // Discard the return value because we assume reading a MemoryStream always succeeds completely. 75 _ = input.Read(ownedMemory.Span); 76 77 return ownedMemory; 78 } 79 80 private static RecyclableMemoryStream StreamToRecyclableMemoryStream(Stream input) 81 { 82 RecyclableMemoryStream stream = MemoryStreamManager.Shared.GetStream(); 83 84 input.CopyTo(stream); 85 86 return stream; 87 } 88 } 89 }