Ejemplo n.º 1
0
        public async Task BuildDeltaAsync(Stream newFileStream, ISignatureReader signatureReader, IDeltaWriter deltaWriter)
        {
            var signature = signatureReader.ReadSignature();
            var chunks    = signature.Chunks;

            var newFileVerificationHashAlgorithm = SupportedAlgorithms.Hashing.Md5();
            var newFileHash = await newFileVerificationHashAlgorithm.ComputeHashAsync(newFileStream).ConfigureAwait(false);

            newFileStream.Seek(0, SeekOrigin.Begin);

            deltaWriter.WriteMetadata(new DeltaMetadata
            {
                HashAlgorithm             = signature.HashAlgorithm.Name,
                ExpectedFileHashAlgorithm = newFileVerificationHashAlgorithm.Name,
                ExpectedFileHash          = Convert.ToBase64String(newFileHash)
            });

            chunks = OrderChunksByChecksum(chunks);

            var chunkMap = CreateChunkMap(chunks, out int maxChunkSize, out int minChunkSize);

            var  buffer            = new byte[readBufferSize];
            long lastMatchPosition = 0;

            var fileSize = newFileStream.Length;

            ProgressReport?.Report(new ProgressReport
            {
                Operation       = ProgressOperationType.BuildingDelta,
                CurrentPosition = 0,
                Total           = fileSize
            });

            while (true)
            {
                var startPosition = newFileStream.Position;
                var read          = await newFileStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);

                if (read < 0)
                {
                    break;
                }

                var  checksumAlgorithm = signature.RollingChecksumAlgorithm;
                uint checksum          = 0;

                var remainingPossibleChunkSize = maxChunkSize;

                for (var i = 0; i < read - minChunkSize + 1; i++)
                {
                    var readSoFar = startPosition + i;

                    var remainingBytes = read - i;
                    if (remainingBytes < maxChunkSize)
                    {
                        remainingPossibleChunkSize = minChunkSize;
                    }

                    if (i == 0 || remainingBytes < maxChunkSize)
                    {
                        checksum = checksumAlgorithm.Calculate(buffer, i, remainingPossibleChunkSize);
                    }
                    else
                    {
                        var remove = buffer[i - 1];
                        var add    = buffer[i + remainingPossibleChunkSize - 1];
                        checksum = checksumAlgorithm.Rotate(checksum, remove, add, remainingPossibleChunkSize);
                    }

                    ProgressReport?.Report(new ProgressReport
                    {
                        Operation       = ProgressOperationType.BuildingDelta,
                        CurrentPosition = readSoFar,
                        Total           = fileSize
                    });

                    if (readSoFar - (lastMatchPosition - remainingPossibleChunkSize) < remainingPossibleChunkSize)
                    {
                        continue;
                    }

                    if (!chunkMap.ContainsKey(checksum))
                    {
                        continue;
                    }

                    var startIndex = chunkMap[checksum];

                    for (var j = startIndex; j < chunks.Count && chunks[j].RollingChecksum == checksum; j++)
                    {
                        var chunk = chunks[j];
                        var hash  = signature.HashAlgorithm.ComputeHash(buffer, i, remainingPossibleChunkSize);

                        if (StructuralComparisons.StructuralEqualityComparer.Equals(hash, chunks[j].Hash))
                        {
                            readSoFar = readSoFar + remainingPossibleChunkSize;

                            var missing = readSoFar - lastMatchPosition;
                            if (missing > remainingPossibleChunkSize)
                            {
                                await deltaWriter.WriteDataCommandAsync(newFileStream, lastMatchPosition, missing - remainingPossibleChunkSize).ConfigureAwait(false);
                            }

                            deltaWriter.WriteCopyCommand(new DataRange(chunk.StartOffset, chunk.Length));
                            lastMatchPosition = readSoFar;
                            break;
                        }
                    }
                }

                if (read < buffer.Length)
                {
                    break;
                }

                newFileStream.Position = newFileStream.Position - maxChunkSize + 1;
            }

            if (newFileStream.Length != lastMatchPosition)
            {
                await deltaWriter.WriteDataCommandAsync(newFileStream, lastMatchPosition, newFileStream.Length - lastMatchPosition).ConfigureAwait(false);
            }

            deltaWriter.Finish();
        }
Ejemplo n.º 2
0
 public async Task WriteDataCommandAsync(Stream source, long offset, long length)
 {
     FlushCurrentCopyCommand();
     await decorated.WriteDataCommandAsync(source, offset, length).ConfigureAwait(false);
 }