Click here to Skip to main content
13,343,856 members (75,371 online)
Click here to Skip to main content
Add your own
alternative version


17 bookmarked
Posted 1 Sep 2009


, 1 Sep 2009
Rate this:
Please Sign up or sign in to vote.
A reusable delta engine with GDI+ front-end controls.


This is a candidate entry for The Code Project's Lean and Mean competition to write an efficient text delta tool.

I was checking my emails while on vacation and I came across a Code Project daily mailing with a reminder for the LCS competition. I have enjoyed reading The Code Project articles for many years now, but until this moment I never had the opportunity to contribute.

When I first started with C# I decided to write a diff program in order to really learn the language. I call this program, DeltaScope. What started out as a simple console-based diff tool has gone through many iterations. When I finally stopped work on it, I had a reusable delta engine with GDI+ front-end controls.

Unfortunately, I have not touched this code since 2005. Thankfully my fiancé is very understanding of my “coding time” and I was able to take some time to write this article and bring the code up to C# 3.0 specifications.

Longest Common Subsequence

Many of the entries have excellent explanations of the LCS algorithm. When I wrote my DeltaScope I referred to this paper extensively.[^]

I find the best way to understand the LCS algorithm, is to think of it like this:
The output of a delta operation is a sequence of instructions to transform file 1 into file 2.

Points of Interest

The core of the system is the DeltaEngine class. The DeltaScope application wraps up the engine in the DeltaScopeEngine class.

public class DeltaScopeEngine 
        public bool IgnoreCase { get; set; }
        public bool IgnoreTabs { get; set; }

        public TimeSpan ElapsedTime { get; private set; }
        public long PeakMemoryUsage { get; private set; }

        public List<DeltaBlock> Compare(string tsLeftFile, string tsRightFile)
            var process = Process.GetCurrentProcess();
            var peakWorkingSet64 = process.PeakWorkingSet64;

            var timer = DateTime.Now;
            var deltaEngine = new DeltaEngine();
            var result = deltaEngine.GetDifferences(RipFile(tsLeftFile),
                RipFile(tsRightFile), hashSideDelegate);
            ElapsedTime = DateTime.Now - timer;
            PeakMemoryUsage = process.PeakWorkingSet64 - peakWorkingSet64;
            return result;
        private static string RipFile(string tsFileName)
        private List<DeltaString> hashSideDelegate(string sideValues)
            const string blockLineTerminator = @"\r\n";
            var values = new List<string>(Regex.Split(sideValues, blockLineTerminator));
            var results = new List<DeltaString>();

            for (var lnCnt = 0; lnCnt < values.Count; lnCnt++)
                var lnHashCode = _GenerateHashFromString(values[lnCnt]);
                if (lnHashCode >= 0)
                    results.Add(new DeltaString(values[lnCnt], lnHashCode));
            return results;
        private int _GenerateHashFromString(string tsLine)
            var lnHash = 0;
            var lnRealPtr = 0;
            // Handle the upper casing issue...
            var lcaLine = IgnoreCase ? 
                tsLine.ToUpper().ToCharArray() : tsLine.ToCharArray();

            // hash_string(ABCW) = 65*1 + 66*2 + 67*3 + 87*4
            var lnMaxLength = lcaLine.Length;
            for (var lnCnt = 0; lnCnt < lnMaxLength; lnCnt++)
                // Handle the white space characters...
                if (lcaLine[lnCnt] == '\t' && IgnoreTabs)

                lnHash += ((byte)lcaLine[lnCnt] * lnRealPtr);

            // return the hash value...
            return (lnHash);

The hashAlgorithm delegate lets the developer control how each string is parsed into a list of DeltaStrings. In this simple example we can choose to make the difference case sensative or case insensative, and we can choose to ignore tab characters.

Timings and Memory Consumption

The average run timing is 13ms. I do not include any screen rendering in my timings. As for memory consumption, I always come up with 0 memory used. Which means I am either not using process.PeakWorkingSet64 correctly, or my code is magical. ;)

Future direction

Many diff tools allow the user to merge the 2 files into 1 new file. With the list of delta blocks that the DeltaEngine generates, it should be possible to allow the user to build a new file. This would require some sort of block choosing ability along with perhaps text editing. Unfortunately the current GDI+ controls are display only.

When I initially wrote this, GDI+ was a pretty new technology, and WPF did not yet exist. I think a good next step would be to use WPF as the display technology for the display. With WPF the swirl block control can be rewritten to include editing abilities.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer (Senior)
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

Questionvery cool UI Pin
dmihailescu4-Aug-15 7:50
memberdmihailescu4-Aug-15 7:50 
AnswerRe: very cool UI Pin
NYCChris4-Aug-15 10:37
memberNYCChris4-Aug-15 10:37 
GeneralPrinting Pin
StevePasha14-Jul-10 20:10
memberStevePasha14-Jul-10 20:10 
GeneralRe: Printing Pin
Christopher Erker15-Jul-10 9:29
memberChristopher Erker15-Jul-10 9:29 
GeneralRe: Printing Pin
StevePasha16-Jul-10 9:37
memberStevePasha16-Jul-10 9:37 
GeneralSource does not build for me due to missing App.Config in the DeltaEngine project Pin
Sacha Barber3-Sep-09 4:51
mvpSacha Barber3-Sep-09 4:51 
GeneralRe: Source does not build for me due to missing App.Config in the DeltaEngine project Pin
Christopher Erker3-Sep-09 6:57
memberChristopher Erker3-Sep-09 6:57 
GeneralRe: Source does not build for me due to missing App.Config in the DeltaEngine project Pin
Sacha Barber3-Sep-09 7:11
mvpSacha Barber3-Sep-09 7:11 
GeneralRe: Source does not build for me due to missing App.Config in the DeltaEngine project Pin
Christopher Erker3-Sep-09 7:40
memberChristopher Erker3-Sep-09 7:40 
Generalmetrics Pin
Luc Pattyn2-Sep-09 17:28
mvpLuc Pattyn2-Sep-09 17:28 
GeneralRe: metrics Pin
Christopher Erker2-Sep-09 17:33
memberChristopher Erker2-Sep-09 17:33 
GeneralRe: metrics Pin
Luc Pattyn2-Sep-09 17:38
mvpLuc Pattyn2-Sep-09 17:38 
GeneralRe: metrics Pin
Christopher Erker2-Sep-09 20:08
memberChristopher Erker2-Sep-09 20:08 
GeneralRe: metrics Pin
Christopher Erker4-Sep-09 10:19
memberChristopher Erker4-Sep-09 10:19 
Generalerror Pin
mandimandi2-Sep-09 1:01
membermandimandi2-Sep-09 1:01 
GeneralRe: error Pin
Christopher Erker2-Sep-09 3:45
memberChristopher Erker2-Sep-09 3:45 
GeneralRe: error Pin
mandimandi2-Sep-09 7:56
membermandimandi2-Sep-09 7:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.180111.1 | Last Updated 1 Sep 2009
Article Copyright 2009 by NYCChris
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid