public void BuildDelta(Stream newFileStream, IOctodiffSignatureReader signatureReader, IOctodiffDeltaWriter deltaWriter)
        {
            var signature = signatureReader.ReadSignature();
            var chunks    = signature.Chunks;

            var newFileHash = signature.HashAlgorithm.ComputeHash(newFileStream);

            newFileStream.Seek(0, SeekOrigin.Begin);

            deltaWriter.WriteMetadata(signature.HashAlgorithm, newFileHash);

            chunks = OrderChunksByChecksum(chunks);

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

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

            while (true)
            {
                var startPosition = newFileStream.Position;
                var read          = newFileStream.Read(buffer, 0, buffer.Length);
                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);
                    }

                    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)
                            {
                                deltaWriter.WriteDataCommand(newFileStream, lastMatchPosition, missing - remainingPossibleChunkSize);
                            }

                            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)
            {
                deltaWriter.WriteDataCommand(newFileStream, lastMatchPosition, newFileStream.Length - lastMatchPosition);
            }

            deltaWriter.Finish();
        }
Example #2
0
 public void WriteMetadata(IHashAlgorithm hashAlgorithm, byte[] expectedNewFileHash)
 {
     decorated.WriteMetadata(hashAlgorithm, expectedNewFileHash);
 }