AuthenticatedRegionCryptoStream
using Azure.Core.Pipeline;
using Azure.Storage.Cryptography.Models;
using System;
using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
namespace Azure.Storage.Cryptography
{
    internal class AuthenticatedRegionCryptoStream : Stream
    {
        private readonly Stream _innerStream;
        private readonly CryptoStreamMode _mode;
        private readonly IAuthenticatedCryptographicTransform _transform;
        private bool _flushedFinal;
        private readonly byte[] _buffer;
        private int _bufferPos;
        private int _bufferPopulatedLength;
        private readonly int _bufferLength;
        private readonly int _tempRefillBufferSize;
        public override bool CanRead => _mode == CryptoStreamMode.Read;
        public override bool CanWrite {
            get {
                if (_mode == CryptoStreamMode.Write)
                    return !_flushedFinal;
                return false;
            }
        }
        public override bool CanSeek => false;
        public override long Length {
            get {
                throw new NotSupportedException();
            }
        }
        public override long Position {
            get {
                throw new NotSupportedException();
            }
            set {
                throw new NotSupportedException();
            }
        }
        public AuthenticatedRegionCryptoStream(Stream innerStream, IAuthenticatedCryptographicTransform transform, int regionDataSize, CryptoStreamMode streamMode)
        {
            _innerStream = innerStream;
            _transform = transform;
            _mode = streamMode;
            int num;
            if ((transform.TransformMode == TransformMode.Encrypt && streamMode == CryptoStreamMode.Write) || (transform.TransformMode == TransformMode.Decrypt && streamMode == CryptoStreamMode.Read)) {
                num = regionDataSize;
                _tempRefillBufferSize = transform.NonceLength + regionDataSize + transform.TagLength;
            } else {
                if ((transform.TransformMode != 0 || streamMode != 0) && (transform.TransformMode != TransformMode.Decrypt || streamMode != CryptoStreamMode.Write))
                    throw Errors.InvalidArgument("transform");
                num = transform.NonceLength + regionDataSize + transform.TagLength;
                _tempRefillBufferSize = regionDataSize;
            }
            _buffer = ArrayPool<byte>.Shared.Rent(num);
            _bufferLength = num;
            _bufferPopulatedLength = _bufferLength;
            int bufferPos;
            switch (streamMode) {
            case CryptoStreamMode.Read:
                bufferPos = _bufferLength;
                break;
            case CryptoStreamMode.Write:
                bufferPos = 0;
                break;
            default:
                throw Errors.InvalidArgument("streamMode");
            }
            _bufferPos = bufferPos;
        }
        public override int Read(byte[] buffer, int offset, int count)
        {
            return ReadInternal(buffer, offset, count, false, default(CancellationToken)).EnsureCompleted();
        }
        [AsyncStateMachine(typeof(<ReadAsync>d__22))]
        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            <ReadAsync>d__22 stateMachine = default(<ReadAsync>d__22);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
            stateMachine.<>4__this = this;
            stateMachine.buffer = buffer;
            stateMachine.offset = offset;
            stateMachine.count = count;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        [AsyncStateMachine(typeof(<ReadInternal>d__23))]
        private Task<int> ReadInternal(byte[] buffer, int offset, int count, bool async, CancellationToken cancellationToken)
        {
            <ReadInternal>d__23 stateMachine = default(<ReadInternal>d__23);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
            stateMachine.<>4__this = this;
            stateMachine.buffer = buffer;
            stateMachine.offset = offset;
            stateMachine.count = count;
            stateMachine.async = async;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        public override void Write(byte[] buffer, int offset, int count)
        {
            WriteInternal(buffer, offset, count, false, default(CancellationToken)).EnsureCompleted();
        }
        [AsyncStateMachine(typeof(<WriteAsync>d__25))]
        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            <WriteAsync>d__25 stateMachine = default(<WriteAsync>d__25);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
            stateMachine.<>4__this = this;
            stateMachine.buffer = buffer;
            stateMachine.offset = offset;
            stateMachine.count = count;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        [AsyncStateMachine(typeof(<WriteInternal>d__26))]
        private Task WriteInternal(byte[] buffer, int offset, int count, bool async, CancellationToken cancellationToken)
        {
            <WriteInternal>d__26 stateMachine = default(<WriteInternal>d__26);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
            stateMachine.<>4__this = this;
            stateMachine.buffer = buffer;
            stateMachine.offset = offset;
            stateMachine.count = count;
            stateMachine.async = async;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        public override void Flush()
        {
            if (FlushToInnerIfReady(false, default(CancellationToken)).EnsureCompleted())
                _innerStream.Flush();
        }
        [AsyncStateMachine(typeof(<FlushAsync>d__28))]
        public override Task FlushAsync(CancellationToken cancellationToken)
        {
            <FlushAsync>d__28 stateMachine = default(<FlushAsync>d__28);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
            stateMachine.<>4__this = this;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        [AsyncStateMachine(typeof(<FlushToInnerIfReady>d__29))]
        private Task<bool> FlushToInnerIfReady(bool async, CancellationToken cancellationToken)
        {
            <FlushToInnerIfReady>d__29 stateMachine = default(<FlushToInnerIfReady>d__29);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder<bool>.Create();
            stateMachine.<>4__this = this;
            stateMachine.async = async;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        [AsyncStateMachine(typeof(<FlushFinalInternal>d__30))]
        public Task FlushFinalInternal(bool async, CancellationToken cancellationToken)
        {
            <FlushFinalInternal>d__30 stateMachine = default(<FlushFinalInternal>d__30);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
            stateMachine.<>4__this = this;
            stateMachine.async = async;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new NotSupportedException();
        }
        public override void SetLength(long value)
        {
            throw new NotSupportedException();
        }
        protected override void Dispose(bool disposing)
        {
            if (CanWrite)
                FlushFinalInternal(false, default(CancellationToken)).EnsureCompleted();
            ArrayPool<byte>.Shared.Return(_buffer, false);
            base.Dispose(disposing);
            _transform.Dispose();
            _innerStream?.Dispose();
        }
    }
}