| | 1 | | #pragma warning disable SA1636 // File header copyright text should match |
| | 2 | | // Licensed to the .NET Foundation under one or more agreements. |
| | 3 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | 4 | | #pragma warning restore SA1636 // File header copyright text should match |
| | 5 | |
|
| | 6 | | using System; |
| | 7 | | using System.IO; |
| | 8 | | using System.Threading; |
| | 9 | | using System.Threading.Tasks; |
| | 10 | |
|
| | 11 | | namespace Azure.Core |
| | 12 | | { |
| | 13 | | /// <summary>Provides a <see cref="Stream"/> for the contents of a <see cref="ReadOnlyMemory{Byte}"/>.</summary> |
| | 14 | | internal sealed class ReadOnlyMemoryStream : Stream |
| | 15 | | { |
| | 16 | | private readonly ReadOnlyMemory<byte> _content; |
| | 17 | | private int _position; |
| | 18 | |
|
| 120 | 19 | | public ReadOnlyMemoryStream(ReadOnlyMemory<byte> content) |
| | 20 | | { |
| 120 | 21 | | _content = content; |
| 120 | 22 | | } |
| | 23 | |
|
| 64 | 24 | | public override bool CanRead => true; |
| 56 | 25 | | public override bool CanSeek => true; |
| 4 | 26 | | public override bool CanWrite => false; |
| | 27 | |
|
| 56 | 28 | | public override long Length => _content.Length; |
| | 29 | |
|
| | 30 | | public override long Position |
| | 31 | | { |
| 62 | 32 | | get => _position; |
| | 33 | | set |
| | 34 | | { |
| 10 | 35 | | if (value < 0 || value > int.MaxValue) |
| | 36 | | { |
| 4 | 37 | | throw new ArgumentOutOfRangeException(nameof(value)); |
| | 38 | | } |
| 6 | 39 | | _position = (int)value; |
| 6 | 40 | | } |
| | 41 | | } |
| | 42 | |
|
| | 43 | | public override long Seek(long offset, SeekOrigin origin) |
| | 44 | | { |
| 14 | 45 | | long pos = |
| 14 | 46 | | origin == SeekOrigin.Begin ? offset : |
| 14 | 47 | | origin == SeekOrigin.Current ? _position + offset : |
| 14 | 48 | | origin == SeekOrigin.End ? _content.Length + offset : |
| 14 | 49 | | throw new ArgumentOutOfRangeException(nameof(origin)); |
| | 50 | |
|
| 14 | 51 | | if (pos > int.MaxValue) |
| | 52 | | { |
| 0 | 53 | | throw new ArgumentOutOfRangeException(nameof(offset)); |
| | 54 | | } |
| 14 | 55 | | else if (pos < 0) |
| | 56 | | { |
| 0 | 57 | | throw new IOException("An attempt was made to move the position before the beginning of the stream."); |
| | 58 | | } |
| | 59 | |
|
| 14 | 60 | | _position = (int)pos; |
| 14 | 61 | | return _position; |
| | 62 | | } |
| | 63 | |
|
| | 64 | | public override int ReadByte() |
| | 65 | | { |
| 6 | 66 | | ReadOnlySpan<byte> s = _content.Span; |
| 6 | 67 | | return _position < s.Length ? s[_position++] : -1; |
| | 68 | | } |
| | 69 | |
|
| | 70 | | public override int Read(byte[] buffer, int offset, int count) |
| | 71 | | { |
| 110 | 72 | | ValidateReadArrayArguments(buffer, offset, count); |
| 110 | 73 | | return Read(new Span<byte>(buffer, offset, count)); |
| | 74 | | } |
| | 75 | |
|
| | 76 | | private int Read(Span<byte> buffer) |
| | 77 | | { |
| 228 | 78 | | int remaining = _content.Length - _position; |
| | 79 | |
|
| 228 | 80 | | if (remaining <= 0 || buffer.Length == 0) |
| | 81 | | { |
| 108 | 82 | | return 0; |
| | 83 | | } |
| 120 | 84 | | else if (remaining <= buffer.Length) |
| | 85 | | { |
| 120 | 86 | | _content.Span.Slice(_position).CopyTo(buffer); |
| 120 | 87 | | _position = _content.Length; |
| 120 | 88 | | return remaining; |
| | 89 | | } |
| | 90 | | else |
| | 91 | | { |
| 0 | 92 | | _content.Span.Slice(_position, buffer.Length).CopyTo(buffer); |
| 0 | 93 | | _position += buffer.Length; |
| 0 | 94 | | return buffer.Length; |
| | 95 | | } |
| | 96 | | } |
| | 97 | |
|
| | 98 | | public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) |
| | 99 | | { |
| 126 | 100 | | ValidateReadArrayArguments(buffer, offset, count); |
| 118 | 101 | | return cancellationToken.IsCancellationRequested ? |
| 118 | 102 | | Task.FromCanceled<int>(cancellationToken) : |
| 118 | 103 | | Task.FromResult(Read(new Span<byte>(buffer, offset, count))); |
| | 104 | | } |
| | 105 | |
|
| 0 | 106 | | public override void Flush() { } |
| | 107 | |
|
| 0 | 108 | | public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask; |
| | 109 | |
|
| 0 | 110 | | public override void SetLength(long value) => throw new NotSupportedException(); |
| | 111 | |
|
| 4 | 112 | | public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); |
| | 113 | |
|
| | 114 | | private static void ValidateReadArrayArguments(byte[] buffer, int offset, int count) |
| | 115 | | { |
| 236 | 116 | | if (buffer == null) |
| | 117 | | { |
| 2 | 118 | | throw new ArgumentNullException(nameof(buffer)); |
| | 119 | | } |
| 234 | 120 | | if (offset < 0) |
| | 121 | | { |
| 2 | 122 | | throw new ArgumentOutOfRangeException(nameof(offset)); |
| | 123 | | } |
| 232 | 124 | | if (count < 0 || buffer.Length - offset < count) |
| | 125 | | { |
| 4 | 126 | | throw new ArgumentOutOfRangeException(nameof(count)); |
| | 127 | | } |
| 228 | 128 | | } |
| | 129 | | } |
| | 130 | | } |