public void Update_ThrowsAfterGetHashCalled()
        {
            using (var hashFunc = new Sha512HashFunction())
            {
                hashFunc.Update(_input, 0, count: 1);
                hashFunc.GetHash();

                Assert.Throws <InvalidOperationException>(() => hashFunc.Update(_input, 1, count: 1));
            }
        }
        public void Update_SupportsIncrementalUpdates()
        {
            using (var hashFunc = new Sha512HashFunction())
            {
                for (var i = 0; i < _input.Length; ++i)
                {
                    hashFunc.Update(_input, i, count: 1);
                }

                var actualResult = hashFunc.GetHash();

                Assert.Equal(_expectedResult, actualResult);
            }
        }
        /// <summary>
        /// Hashes given byte array with a specified HashAlgorithm wrapper which works cross platform.
        /// </summary>
        /// <param name="hashFunc">HashAlgorithm wrapper used to hash contents cross platform</param>
        /// <param name="bytes">Content to hash</param>
        internal static void HashBytes(Sha512HashFunction hashFunc, byte[] bytes)
        {
            if (hashFunc == null)
            {
                throw new ArgumentNullException(nameof(hashFunc));
            }

            if (bytes == null || bytes.Length == 0)
            {
                throw new ArgumentException(Strings.ArgumentCannotBeNullOrEmpty, nameof(bytes));
            }

            hashFunc.Update(bytes, 0, bytes.Length);
        }
        /// <summary>
        /// Hashes given byte array with a specified HashAlgorithm wrapper which works cross platform.
        /// </summary>
        /// <param name="hashFunc">HashAlgorithm wrapper used to hash contents cross platform</param>
        /// <param name="bytes">Content to hash</param>
        /// <param name="count">The number of bytes in the input byte array to use as data.</param>
        internal static void HashBytes(Sha512HashFunction hashFunc, byte[] bytes, int count)
        {
            if (hashFunc == null)
            {
                throw new ArgumentNullException(nameof(hashFunc));
            }

            if (bytes == null || bytes.Length == 0)
            {
                throw new ArgumentException(Strings.ArgumentCannotBeNullOrEmpty, nameof(bytes));
            }

            if (count <= 0 || bytes.Length < count)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            hashFunc.Update(bytes, offset: 0, count);
        }
        internal static string GetPackageContentHash(BinaryReader reader)
        {
            using (var hashFunc = new Sha512HashFunction())
            {
                // skip validating signature entry since we're just trying to get the content hash here instead of
                // verifying signature entry.
                var metadata = SignedPackageArchiveIOUtility.ReadSignedArchiveMetadata(reader, validateSignatureEntry: false);
                var signatureCentralDirectoryHeader         = metadata.GetPackageSignatureFileCentralDirectoryHeaderMetadata();
                var centralDirectoryRecordsWithoutSignature = RemoveSignatureAndOrderByOffset(metadata);

                // Read and hash from the start of the archive to the start of the file headers
                reader.BaseStream.Seek(offset: 0, origin: SeekOrigin.Begin);
                SignedPackageArchiveIOUtility.ReadAndHashUntilPosition(reader, hashFunc, metadata.StartOfLocalFileHeaders);

                // Read and hash file headers
                foreach (var record in centralDirectoryRecordsWithoutSignature)
                {
                    reader.BaseStream.Seek(offset: record.OffsetToLocalFileHeader, origin: SeekOrigin.Begin);
                    SignedPackageArchiveIOUtility.ReadAndHashUntilPosition(reader, hashFunc, record.OffsetToLocalFileHeader + record.FileEntryTotalSize);
                }

                // Order central directory records by their position
                centralDirectoryRecordsWithoutSignature.Sort((x, y) => x.Position.CompareTo(y.Position));

                // Update offset of any central directory record that has a file entry after signature
                foreach (var record in centralDirectoryRecordsWithoutSignature)
                {
                    reader.BaseStream.Seek(offset: record.Position, origin: SeekOrigin.Begin);
                    // Hash from the start of the central directory record until the relative offset of local file header (42 from the start of central directory record, including signature length)
                    SignedPackageArchiveIOUtility.ReadAndHashUntilPosition(reader, hashFunc, reader.BaseStream.Position + 42);

                    var relativeOffsetOfLocalFileHeader = (uint)(reader.ReadUInt32() + record.ChangeInOffset);
                    HashUInt32(hashFunc, relativeOffsetOfLocalFileHeader);

                    // Continue hashing file name, extra field, and file comment fields.
                    SignedPackageArchiveIOUtility.ReadAndHashUntilPosition(reader, hashFunc, reader.BaseStream.Position + record.HeaderSize - CentralDirectoryHeader.SizeInBytesOfFixedLengthFields);
                }

                reader.BaseStream.Seek(offset: metadata.EndOfCentralDirectory, origin: SeekOrigin.Begin);

                // Hash until total entries in end of central directory record (8 bytes from the start of EOCDR)
                SignedPackageArchiveIOUtility.ReadAndHashUntilPosition(reader, hashFunc, metadata.EndOfCentralDirectory + 8);

                var eocdrTotalEntries       = (ushort)(reader.ReadUInt16() - 1);
                var eocdrTotalEntriesOnDisk = (ushort)(reader.ReadUInt16() - 1);

                HashUInt16(hashFunc, eocdrTotalEntries);
                HashUInt16(hashFunc, eocdrTotalEntriesOnDisk);

                // update the central directory size by substracting the size of the package signature file's central directory header
                var eocdrSizeOfCentralDirectory = (uint)(reader.ReadUInt32() - signatureCentralDirectoryHeader.HeaderSize);
                HashUInt32(hashFunc, eocdrSizeOfCentralDirectory);

                var eocdrOffsetOfCentralDirectory = reader.ReadUInt32() - (uint)signatureCentralDirectoryHeader.FileEntryTotalSize;
                HashUInt32(hashFunc, eocdrOffsetOfCentralDirectory);

                // Hash until the end of the reader
                SignedPackageArchiveIOUtility.ReadAndHashUntilPosition(reader, hashFunc, reader.BaseStream.Length);

                hashFunc.Update(new byte[0], offset: 0, count: 0);

                return(hashFunc.GetHash());
            }
        }