public static IEnumerable <OutputCommand> ComputeCommands( BinaryReader inputStream, SignatureFile signatures) { OutputCommand currentCommand = new OutputCommand { Kind = CommandKind.Reserved }; Rollsum currentSum; Queue <byte> currentBlock; // Read the first block to initialize ReadNewBlock(inputStream, signatures.BlockLength, out currentBlock, out currentSum); while (currentBlock.Count > 0) { // if the block has a matching rolling sum to any contained in the signature, those are candidates var matchCandidates = signatures.BlockLookup[currentSum.Digest]; bool wasMatch = false; if (matchCandidates.Any()) { // now compute the strong sum and see if any of the signature blocks match it byte[] currentStrongSum = signatures.StrongSumMethod(currentBlock.ToArray()).Take(signatures.StrongSumLength).ToArray(); var matchingBlock = matchCandidates.FirstOrDefault(s => s.StrongSum.SequenceEqual(currentStrongSum)); // if one of the signature blocks was a match, we can generate a Copy command if (matchingBlock != null) { if (currentCommand.Kind == CommandKind.Copy && currentCommand.Position + currentCommand.Length == matchingBlock.StartPos) { // in this case, we can just add this copy onto the previous one currentCommand.Length = currentCommand.Length + (ulong)currentBlock.Count; } else { // if we can't append to the current command, then return the current command and start a new one if (currentCommand.Kind != CommandKind.Reserved) { yield return(currentCommand); } currentCommand = new OutputCommand { Kind = CommandKind.Copy, Position = matchingBlock.StartPos, Length = (ulong)currentBlock.Count }; } // if we found a match, then we read a whole new block and reset the sum to it's hash wasMatch = true; ReadNewBlock(inputStream, signatures.BlockLength, out currentBlock, out currentSum); } } // if there was no match for the current block, the we have to output it's first byte (at least) // as a literal value, and try again starting at the next byte if (!wasMatch) { // pull out the oldest byte byte oldestByte = currentBlock.Dequeue(); // if we're not at the end of the file if (inputStream.BaseStream.Position != inputStream.BaseStream.Length) { // read a byte and add it in, hoping to find a match at the next spot byte nextByte = inputStream.ReadByte(); currentBlock.Enqueue(nextByte); currentSum.Rotate(byteOut: oldestByte, byteIn: nextByte); } else { // if we are at the end of the file, then just rollout the oldestByte and see if we have a match for the partial block // (this could happen if we match the last block in the original file) currentSum.Rollout(byteOut: oldestByte); } if (currentCommand.Kind == CommandKind.Literal && currentCommand.Literal.Count < MaxLiteralLength) { // if we already have a literal command, just append a new byte on currentCommand.Literal.Add(oldestByte); } else { // otherwise we have to emit the current command and start a new literal command if (currentCommand.Kind != CommandKind.Reserved) { yield return(currentCommand); } currentCommand = new OutputCommand { Kind = CommandKind.Literal, Literal = new List <byte> { oldestByte }, }; } } } yield return(currentCommand); yield return(new OutputCommand { Kind = CommandKind.End, }); }
public static IEnumerable<OutputCommand> ComputeCommands( BinaryReader inputStream, SignatureFile signatures) { OutputCommand currentCommand = new OutputCommand { Kind = CommandKind.Reserved }; Rollsum currentSum; Queue<byte> currentBlock; // Read the first block to initialize ReadNewBlock(inputStream, signatures.BlockLength, out currentBlock, out currentSum); while (currentBlock.Count > 0) { // if the block has a matching rolling sum to any contained in the signature, those are candidates var matchCandidates = signatures.BlockLookup[currentSum.Digest]; bool wasMatch = false; if (matchCandidates.Any()) { // now compute the strong sum and see if any of the signature blocks match it byte[] currentStrongSum = signatures.StrongSumMethod(currentBlock.ToArray()).Take(signatures.StrongSumLength).ToArray(); var matchingBlock = matchCandidates.FirstOrDefault(s => s.StrongSum.SequenceEqual(currentStrongSum)); // if one of the signature blocks was a match, we can generate a Copy command if (matchingBlock != null) { if (currentCommand.Kind == CommandKind.Copy && currentCommand.Position + currentCommand.Length == matchingBlock.StartPos) { // in this case, we can just add this copy onto the previous one currentCommand.Length = currentCommand.Length + (ulong)currentBlock.Count; } else { // if we can't append to the current command, then return the current command and start a new one if (currentCommand.Kind != CommandKind.Reserved) { yield return currentCommand; } currentCommand = new OutputCommand { Kind = CommandKind.Copy, Position = matchingBlock.StartPos, Length = (ulong)currentBlock.Count }; } // if we found a match, then we read a whole new block and reset the sum to it's hash wasMatch = true; ReadNewBlock(inputStream, signatures.BlockLength, out currentBlock, out currentSum); } } // if there was no match for the current block, the we have to output it's first byte (at least) // as a literal value, and try again starting at the next byte if (!wasMatch) { // pull out the oldest byte byte oldestByte = currentBlock.Dequeue(); // if we're not at the end of the file if (inputStream.BaseStream.Position != inputStream.BaseStream.Length) { // read a byte and add it in, hoping to find a match at the next spot byte nextByte = inputStream.ReadByte(); currentBlock.Enqueue(nextByte); currentSum.Rotate(byteOut: oldestByte, byteIn: nextByte); } else { // if we are at the end of the file, then just rollout the oldestByte and see if we have a match for the partial block // (this could happen if we match the last block in the original file) currentSum.Rollout(byteOut: oldestByte); } if (currentCommand.Kind == CommandKind.Literal && currentCommand.Literal.Count < MaxLiteralLength) { // if we already have a literal command, just append a new byte on currentCommand.Literal.Add(oldestByte); } else { // otherwise we have to emit the current command and start a new literal command if (currentCommand.Kind != CommandKind.Reserved) { yield return currentCommand; } currentCommand = new OutputCommand { Kind = CommandKind.Literal, Literal = new List<byte> { oldestByte }, }; } } } yield return currentCommand; yield return new OutputCommand { Kind = CommandKind.End, }; }
public static IEnumerable <OutputCommand> ComputeCommands(BinaryReader inputStream, SignatureFile signatures) { OutputCommand outputCommand = default(OutputCommand); outputCommand.Kind = CommandKind.Reserved; OutputCommand outputCommand2 = outputCommand; long inputLength = inputStream.BaseStream.Length; ReadNewBlock(inputStream, signatures.BlockLength, out Queue <byte> currentBlock, out Rollsum currentSum); while (currentBlock.Count > 0) { List <BlockSignature> value = null; bool flag = false; if (signatures.BlockLookup.TryGetValue(currentSum.Digest, out value)) { byte[] currentStrongSum = signatures.StrongSumMethod(currentBlock.ToArray()); BlockSignature matchingBlock = FindBlockSignatureByStrongSum(value, currentStrongSum); if (matchingBlock != null) { if (outputCommand2.Kind == CommandKind.Copy && outputCommand2.Position + outputCommand2.Length == matchingBlock.StartPos) { outputCommand2.Length = (ulong)((long)outputCommand2.Length + (long)currentBlock.Count); } else { if (outputCommand2.Kind != CommandKind.Reserved) { yield return(outputCommand2); } outputCommand = default(OutputCommand); outputCommand.Kind = CommandKind.Copy; outputCommand.Position = matchingBlock.StartPos; outputCommand.Length = (ulong)currentBlock.Count; outputCommand2 = outputCommand; } flag = true; ReadNewBlock(inputStream, signatures.BlockLength, out currentBlock, out currentSum); } } if (!flag) { byte oldestByte = currentBlock.Dequeue(); if (inputStream.BaseStream.Position != inputLength) { byte b = inputStream.ReadByte(); currentBlock.Enqueue(b); currentSum.Rotate(oldestByte, b); } else { currentSum.Rollout(oldestByte); } if (outputCommand2.Kind == CommandKind.Literal && outputCommand2.Literal.Count < 4194304) { outputCommand2.Literal.Add(oldestByte); } else { if (outputCommand2.Kind != CommandKind.Reserved) { yield return(outputCommand2); } outputCommand = default(OutputCommand); outputCommand.Kind = CommandKind.Literal; outputCommand.Literal = new List <byte> { oldestByte }; outputCommand2 = outputCommand; } } } yield return(outputCommand2); outputCommand = new OutputCommand { Kind = CommandKind.End }; yield return(outputCommand); }