ContentHasher
Hashes Storage content.
            
                using Azure.Core;
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
namespace Azure.Storage
{
    internal static class ContentHasher
    {
        internal class GetHashResult
        {
            public static GetHashResult Empty { get; } = new GetHashResult(1, default(ReadOnlyMemory<byte>));
            public StorageChecksumAlgorithm Algorithm { get; }
            public ReadOnlyMemory<byte> Checksum { get; }
            public ReadOnlyMemory<byte> MD5 {
                get {
                    if ((int)Algorithm != 2)
                        return default(ReadOnlyMemory<byte>);
                    return Checksum;
                }
            }
            public ReadOnlyMemory<byte> StorageCrc64 {
                get {
                    if ((int)Algorithm != 3)
                        return default(ReadOnlyMemory<byte>);
                    return Checksum;
                }
            }
            public byte[] MD5AsArray {
                get {
                    ReadOnlyMemory<byte> mD = MD5;
                    if (!mD.IsEmpty) {
                        mD = MD5;
                        return mD.ToArray();
                    }
                    return null;
                }
            }
            public byte[] StorageCrc64AsArray {
                get {
                    ReadOnlyMemory<byte> storageCrc = StorageCrc64;
                    if (!storageCrc.IsEmpty) {
                        storageCrc = StorageCrc64;
                        return storageCrc.ToArray();
                    }
                    return null;
                }
            }
            private GetHashResult(StorageChecksumAlgorithm algorithm, ReadOnlyMemory<byte> checksum)
            {
                Algorithm = algorithm;
                Checksum = checksum;
            }
            public static GetHashResult FromStorageCrc64(ReadOnlyMemory<byte> checksum)
            {
                return new GetHashResult(3, checksum);
            }
            public static GetHashResult FromMD5(ReadOnlyMemory<byte> checksum)
            {
                return new GetHashResult(2, checksum);
            }
        }
        public delegate int GetFinalStreamHash (Span<byte> destination);
        internal static int GetHashSizeInBytes(StorageChecksumAlgorithm algorithm)
        {
            StorageChecksumAlgorithm val = algorithm.ResolveAuto();
            switch (val - 1) {
            case 0:
                return 0;
            case 1:
                return 16;
            case 2:
                return 8;
            default:
                throw Errors.InvalidArgument("algorithm");
            }
        }
        internal static UploadTransferValidationOptions ToUploadTransferValidationOptions(this GetHashResult hashResult)
        {
            if (hashResult == null) {
                UploadTransferValidationOptions val = new UploadTransferValidationOptions();
                val.set_ChecksumAlgorithm(1);
                return val;
            }
            UploadTransferValidationOptions val2 = new UploadTransferValidationOptions();
            val2.set_ChecksumAlgorithm(hashResult.Algorithm);
            val2.set_PrecalculatedChecksum(hashResult.Checksum);
            return val2;
        }
        [AsyncStateMachine(typeof(<AssertResponseHashMatchInternal>d__3))]
        public static Task AssertResponseHashMatchInternal(Stream content, StorageChecksumAlgorithm algorithm, Response response, bool async, CancellationToken cancellationToken)
        {
            <AssertResponseHashMatchInternal>d__3 stateMachine = default(<AssertResponseHashMatchInternal>d__3);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
            stateMachine.content = content;
            stateMachine.algorithm = algorithm;
            stateMachine.response = response;
            stateMachine.async = async;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        public static void AssertResponseHashMatch(byte[] content, int offset, int count, StorageChecksumAlgorithm algorithm, Response response)
        {
            AssertResponseHashMatch(GetHash(BinaryData.FromBytes(new ReadOnlyMemory<byte>(content, offset, count)), algorithm), algorithm, response);
        }
        private static void AssertResponseHashMatch(GetHashResult computedHash, StorageChecksumAlgorithm algorithm, Response response)
        {
            if (computedHash == null)
                throw Errors.ArgumentNull("computedHash");
            if (response == null)
                throw Errors.ArgumentNull("response");
            StorageChecksumAlgorithm val = algorithm.ResolveAuto();
            ReadOnlyMemory<byte> readOnlyMemory;
            if ((int)val != 2) {
                if ((int)val != 3)
                    throw Errors.InvalidArgument("algorithm");
                readOnlyMemory = computedHash.StorageCrc64;
                if (!readOnlyMemory.Span.SequenceEqual(response.Headers.TryGetValue("x-ms-content-crc64", out byte[] value) ? value : null))
                    throw Errors.HashMismatch("x-ms-content-crc64");
            } else {
                readOnlyMemory = computedHash.MD5;
                if (!readOnlyMemory.Span.SequenceEqual(response.Headers.TryGetValue("Content-MD5", out byte[] value2) ? value2 : null))
                    throw Errors.HashMismatch("Content-MD5");
            }
        }
        [AsyncStateMachine(typeof(<GetHashOrDefaultInternal>d__6))]
        public static Task<GetHashResult> GetHashOrDefaultInternal(Stream content, UploadTransferValidationOptions options, bool async, CancellationToken cancellationToken)
        {
            <GetHashOrDefaultInternal>d__6 stateMachine = default(<GetHashOrDefaultInternal>d__6);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder<GetHashResult>.Create();
            stateMachine.content = content;
            stateMachine.options = options;
            stateMachine.async = async;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        public static GetHashResult GetHashOrDefault(BinaryData content, UploadTransferValidationOptions options)
        {
            if (GetHashOrDefaultTryFromOptions(options, out GetHashResult result))
                return result;
            return GetHash(content, options.get_ChecksumAlgorithm());
        }
        private static bool GetHashOrDefaultTryFromOptions(UploadTransferValidationOptions options, out GetHashResult result)
        {
            if (options == null || (int)options.get_ChecksumAlgorithm() == 1) {
                result = null;
                return true;
            }
            if (!options.get_PrecalculatedChecksum().IsEmpty) {
                StorageChecksumAlgorithm val = options.get_ChecksumAlgorithm().ResolveAuto();
                GetHashResult getHashResult;
                if ((int)val != 2) {
                    if ((int)val != 3)
                        throw Errors.InvalidArgument("ChecksumAlgorithm");
                    getHashResult = GetHashResult.FromStorageCrc64(options.get_PrecalculatedChecksum());
                } else
                    getHashResult = GetHashResult.FromMD5(options.get_PrecalculatedChecksum());
                result = getHashResult;
                return true;
            }
            result = null;
            return false;
        }
        [AsyncStateMachine(typeof(<GetHashInternal>d__9))]
        public static Task<GetHashResult> GetHashInternal(Stream content, StorageChecksumAlgorithm algorithmIdentifier, bool async, CancellationToken cancellationToken)
        {
            <GetHashInternal>d__9 stateMachine = default(<GetHashInternal>d__9);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder<GetHashResult>.Create();
            stateMachine.content = content;
            stateMachine.algorithmIdentifier = algorithmIdentifier;
            stateMachine.async = async;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        public static GetHashResult GetHash(BinaryData content, StorageChecksumAlgorithm algorithmIdentifier)
        {
            <>c__DisplayClass10_0 <>c__DisplayClass10_ = default(<>c__DisplayClass10_0);
            <>c__DisplayClass10_.content = content;
            StorageChecksumAlgorithm val = algorithmIdentifier.ResolveAuto();
            if ((int)val == 2)
                return GetHashResult.FromMD5(MD5.Create().ComputeHash(<>c__DisplayClass10_.content.ToArray()));
            if ((int)val != 3)
                throw Errors.InvalidArgument("algorithmIdentifier");
            return GetHashResult.FromStorageCrc64(<GetHash>g__computeCrc|10_0(StorageCrc64HashAlgorithm.Create(), ref <>c__DisplayClass10_));
        }
        public static (Stream Stream, GetFinalStreamHash GetCurrentStreamHash, int HashSize, IDisposable Disposable) SetupChecksumCalculatingReadStream(Stream stream, StorageChecksumAlgorithm algorithmIdentifier)
        {
            IHasher hasher = GetHasher(algorithmIdentifier);
            IHasher hasher2 = hasher;
            Stream readStream = ChecksumCalculatingStream.GetReadStream(stream, hasher2.AppendHash);
            IHasher hasher3 = hasher;
            return (readStream, hasher3.GetFinalHash, hasher.HashSizeInBytes, hasher);
        }
        private static IHasher GetHasher(StorageChecksumAlgorithm algorithmIdentifier)
        {
            StorageChecksumAlgorithm val = algorithmIdentifier.ResolveAuto();
            if ((int)val == 2)
                return new HashAlgorithmHasher(MD5.Create());
            if ((int)val != 3)
                throw Errors.InvalidArgument("algorithmIdentifier");
            return new NonCryptographicHashAlgorithmHasher(StorageCrc64HashAlgorithm.Create());
        }
        [AsyncStateMachine(typeof(<ComputeHashInternal>d__14))]
        private static Task<byte[]> ComputeHashInternal(Stream content, IHasher hasher, bool async, CancellationToken cancellationToken)
        {
            <ComputeHashInternal>d__14 stateMachine = default(<ComputeHashInternal>d__14);
            stateMachine.<>t__builder = AsyncTaskMethodBuilder<byte[]>.Create();
            stateMachine.content = content;
            stateMachine.hasher = hasher;
            stateMachine.async = async;
            stateMachine.cancellationToken = cancellationToken;
            stateMachine.<>1__state = -1;
            stateMachine.<>t__builder.Start(ref stateMachine);
            return stateMachine.<>t__builder.Task;
        }
        public static IHasher GetHasherFromAlgorithmId(StorageChecksumAlgorithm algorithm)
        {
            StorageChecksumAlgorithm val = algorithm.ResolveAuto();
            switch (val - 1) {
            case 0:
                return null;
            case 1:
                return new HashAlgorithmHasher(MD5.Create());
            case 2:
                return new NonCryptographicHashAlgorithmHasher(StorageCrc64HashAlgorithm.Create());
            default:
                throw Errors.InvalidArgument("algorithm");
            }
        }
        public static (ReadOnlyMemory<byte> Checksum, StorageChecksumAlgorithm Algorithm) GetResponseChecksumOrDefault(Response response)
        {
            if (response.Headers.TryGetValue("x-ms-content-crc64", out byte[] value))
                return (value, 3);
            if (response.Headers.TryGetValue("Content-MD5", out byte[] value2))
                return (value2, 2);
            return (ReadOnlyMemory<byte>.Empty, 1);
        }
    }
}