/// <summary> /// Class constructor /// </summary> /// <param name="baseFile"></param> /// <param name="list"></param> /// <param name="bytesPerLine"Number of bytes to display per line.></param> public BinaryDiffLines(Stream baseFile, AddCopyCollection list, int bytesPerLine) { this.bytesPerLine = bytesPerLine; baseFile.Seek(0, SeekOrigin.Begin); foreach (IAddCopy entry in list) { if (entry.IsAdd) { // Add A's bytes to VerLines Addition add = (Addition)entry; byte[] bytes = add.GetBytes(); int length = bytes.Length; using (MemoryStream stream = new MemoryStream(bytes, false)) { this.AddBytesFromStream(stream, 0, length, false, true); } // Move the ver position. this.versionPosition += length; } else { Copy copy = (Copy)entry; if (this.basePosition < copy.BaseOffset) { // Add bytes to BaseLines from this.iBasePos to C.iBaseOffset-1 int length = copy.BaseOffset - this.basePosition; this.AddBytesFromStream(baseFile, this.basePosition, length, true, false); this.basePosition += length; } // Add copied bytes to both sets of lines. this.AddBytesFromStream(baseFile, copy.BaseOffset, copy.Length, true, true); // Move the base and version positions. this.basePosition = copy.BaseOffset + copy.Length; this.versionPosition += copy.Length; } } int baseLength = (int)baseFile.Length; if (this.basePosition < baseLength) { // Add bytes to BaseLines from this.iBasePos to this.Base.Length this.AddBytesFromStream(baseFile, this.basePosition, baseLength - this.basePosition, true, false); } }
/// <summary> /// Does a binary diff on the two streams and returns an <see cref="AddCopyCollection"/> /// of the differences. /// </summary> /// <param name="baseFile">The base file.</param> /// <param name="versionFile">The version file.</param> /// <returns>An AddCopyCollection that can be used later to construct the version file from the base file.</returns> public AddCopyCollection Execute(Stream baseFile, Stream versionFile, IDiffProgress progress) { if (!baseFile.CanSeek || !versionFile.CanSeek) { throw new ArgumentException("The Base and Version streams must support seeking."); } TableEntry[] table = new TableEntry[this.tableSize]; List <IAddCopy> list = new List <IAddCopy>(); AddCopyCollection result = new AddCopyCollection(list); baseFile.Seek(0, SeekOrigin.Begin); versionFile.Seek(0, SeekOrigin.End); int verPos = 0; int basePos = 0; int verStart = 0; bool isBaseActive = true; uint verHash = 0; uint baseHash = 0; int lastVerHashPos = 0; int lastBaseHashPos = 0; while (verPos <= (versionFile.Length - this.footprintLength)) { progress.Token.ThrowIfCancellationRequested(); // The GetTableEntry procedure will add the entry if it isn't already there. // This gives us a default behavior of favoring the first match. verHash = this.Footprint(versionFile, verPos, verHash, ref lastVerHashPos); TableEntry verEntry = GetTableEntry(table, verHash, versionFile, verPos); TableEntry baseEntry = null; if (isBaseActive) { baseHash = this.Footprint(baseFile, basePos, baseHash, ref lastBaseHashPos); baseEntry = GetTableEntry(table, baseHash, baseFile, basePos); } if (baseFile == verEntry.File && Verify(baseFile, verEntry.Offset, versionFile, verPos)) { int length = this.EmitCodes(verEntry.Offset, verPos, verStart, baseFile, versionFile, list); basePos = verEntry.Offset + length; verPos += length; verStart = verPos; FlushTable(table); continue; } else if (this.favorLastMatch) { verEntry.Offset = verPos; verEntry.File = versionFile; } isBaseActive = isBaseActive && (basePos <= (baseFile.Length - this.footprintLength)); if (isBaseActive) { if (versionFile == baseEntry.File && Verify(versionFile, baseEntry.Offset, baseFile, basePos) && verStart <= baseEntry.Offset) { int length = this.EmitCodes(basePos, baseEntry.Offset, verStart, baseFile, versionFile, list); verPos = baseEntry.Offset + length; basePos += length; verStart = verPos; FlushTable(table); continue; } else if (this.favorLastMatch) { baseEntry.Offset = basePos; baseEntry.File = baseFile; } } verPos++; basePos++; } this.EmitCodes((int)baseFile.Length, (int)versionFile.Length, verStart, baseFile, versionFile, list); Debug.Assert( result.TotalByteLength == (int)versionFile.Length, "The total byte length of the AddCopyCollection MUST equal the length of the version file!"); return(result); }