ADD: Binary compare - navigate through differences

This commit is contained in:
Alexander Koblov 2014-01-08 10:25:44 +00:00
commit fee5c36bc8
3 changed files with 203 additions and 75 deletions

View file

@ -38,7 +38,7 @@
a) File mapping blocks writing into file by other processes.
Either:
+ Open small text files by reading them all into memory (done).
- Change file mapping to custom loading/caching portions of file in memory
- Add optional custom loading/caching portions of file in memory
and only reading from file when neccessary.
b) Searching in Unicode encodings and case-insensitive searching.

View file

@ -196,8 +196,12 @@ type
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure FormResize(Sender: TObject);
private
BinaryDiffList: TFPList;
BinaryDiffIndex: Integer;
BinaryCompare: TBinaryCompare;
BinaryViewerLeft,
BinaryViewerRight: TBinaryDiffViewer;
procedure BinaryCompareFinish;
private
Diff: TDiff;
SynDiffEditActive: TSynDiffEdit;
@ -287,11 +291,24 @@ var
LineNumberLeft,
LineNumberRight: PtrInt;
begin
if not actBinaryCompare.Checked then
try
if actBinaryCompare.Checked then
begin
actStartCompare.Enabled := False;
actCancelCompare.Enabled := True;
BinaryCompare:= TBinaryCompare.Create(BinaryViewerLeft.GetDataAdr,
BinaryViewerRight.GetDataAdr,
BinaryViewerLeft.FileSize,
BinaryViewerRight.FileSize,
BinaryDiffList);
BinaryCompare.OnFinish:= @BinaryCompareFinish;
BinaryCompare.Start;
end
else try
Inc(ScrollLock);
Screen.Cursor := crHourGlass;
if (Length(HashListLeft) = 0) or (Length(HashListRight) = 0) then Exit;
actStartCompare.Enabled := False;
actCancelCompare.Enabled := True;
Diff.Execute(
@ -340,6 +357,7 @@ begin
SynDiffEditLeft.FinishCompare;
SynDiffEditRight.FinishCompare;
Screen.Cursor := crDefault;
actStartCompare.Enabled := True;
actCancelCompare.Enabled := False;
Dec(ScrollLock);
end;
@ -444,13 +462,6 @@ begin
actPaintBackground.Enabled:= not actBinaryCompare.Checked;
actLineDifferences.Enabled:= not actBinaryCompare.Checked;
// Temporarily while not implemented ---------------------
actNextDifference.Enabled:= not actBinaryCompare.Checked;
actPrevDifference.Enabled:= not actBinaryCompare.Checked;
actFirstDifference.Enabled:= not actBinaryCompare.Checked;
actLastDifference.Enabled:= not actBinaryCompare.Checked;
// -------------------------------------------------------
SynDiffEditLeft.Visible:= not actBinaryCompare.Checked;
SynDiffEditRight.Visible:= not actBinaryCompare.Checked;
BinaryViewerLeft.Visible:= actBinaryCompare.Checked;
@ -474,7 +485,15 @@ end;
procedure TfrmDiffer.actCancelCompareExecute(Sender: TObject);
begin
Diff.Cancel;
if not actBinaryCompare.Checked then
Diff.Cancel
else begin
if Assigned(BinaryCompare) then
begin
BinaryCompare.Terminate;
BinaryCompare:= nil;
end;
end;
end;
procedure TfrmDiffer.actAboutExecute(Sender: TObject);
@ -605,6 +624,7 @@ begin
// Set active editor
SynDiffEditActive:= SynDiffEditLeft;
BinaryDiffList:= TFPList.Create;
BinaryViewerLeft:= TBinaryDiffViewer.Create(Self);
BinaryViewerRight:= TBinaryDiffViewer.Create(Self);
@ -644,7 +664,8 @@ end;
procedure TfrmDiffer.FormDestroy(Sender: TObject);
begin
FreeThenNil(Diff);
FreeAndNil(Diff);
FreeAndNil(BinaryDiffList);
end;
procedure TfrmDiffer.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
@ -661,6 +682,18 @@ begin
pnlLeft.Width:= (ClientWidth div 2) - (Splitter.Width div 2);
end;
procedure TfrmDiffer.BinaryCompareFinish;
begin
BinaryCompare:= nil;
BinaryDiffIndex:= -1;
StatusBar.Panels[0].Text := EmptyStr;
StatusBar.Panels[1].Text := ' Modifies: ' + IntToStr(BinaryDiffList.Count);
StatusBar.Panels[2].Text := EmptyStr;
StatusBar.Panels[3].Text := EmptyStr;
actStartCompare.Enabled := True;
actCancelCompare.Enabled := False;
end;
procedure TfrmDiffer.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
CloseAction:= caFree;
@ -720,20 +753,32 @@ var
Line: Integer;
Kind: TChangeKind;
begin
// Start at first line
Line := 0;
if Line = SynDiffEditLeft.Lines.Count then Exit;
// Skip unmodified lines
Kind := ckNone;
while (Line < SynDiffEditLeft.Lines.Count - 1) and
(SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line);
Inc(Line);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
if not actKeepScrolling.Checked then
if actBinaryCompare.Checked then
begin
SynDiffEditRight.TopLine := Line;
SynDiffEditRight.CaretY := Line;
if BinaryDiffList.Count > 0 then
begin
BinaryDiffIndex:= 0;
BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
if not actKeepScrolling.Checked then
BinaryViewerRight.Position:= BinaryViewerLeft.Position;
end;
end
else begin
// Start at first line
Line := 0;
if Line = SynDiffEditLeft.Lines.Count then Exit;
// Skip unmodified lines
Kind := ckNone;
while (Line < SynDiffEditLeft.Lines.Count - 1) and
(SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line);
Inc(Line);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
if not actKeepScrolling.Checked then
begin
SynDiffEditRight.TopLine := Line;
SynDiffEditRight.CaretY := Line;
end;
end;
end;
@ -742,21 +787,33 @@ var
Line: Integer;
Kind: TChangeKind;
begin
Line := SynDiffEditLeft.Lines.Count - 1;
if Line = 0 then Exit;
// Skip unmodified lines
Kind := ckNone;
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
// Find top line of previous difference
Kind:= SynDiffEditLeft.Lines.Kind[Line];
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
if (Line <> 0) then Inc(Line, 2);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
if not actKeepScrolling.Checked then
if actBinaryCompare.Checked then
begin
SynDiffEditRight.TopLine := Line;
SynDiffEditRight.CaretY := Line;
if BinaryDiffList.Count > 0 then
begin
BinaryDiffIndex:= BinaryDiffList.Count - 1;
BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
if not actKeepScrolling.Checked then
BinaryViewerRight.Position:= BinaryViewerLeft.Position;
end;
end
else begin
Line := SynDiffEditLeft.Lines.Count - 1;
if Line = 0 then Exit;
// Skip unmodified lines
Kind := ckNone;
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
// Find top line of previous difference
Kind:= SynDiffEditLeft.Lines.Kind[Line];
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
if (Line <> 0) then Inc(Line, 2);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
if not actKeepScrolling.Checked then
begin
SynDiffEditRight.TopLine := Line;
SynDiffEditRight.CaretY := Line;
end;
end;
end;
@ -765,26 +822,38 @@ var
Line: Integer;
Kind: TChangeKind;
begin
Line := SynDiffEditLeft.CaretY - 1;
if Line = SynDiffEditLeft.Lines.Count - 1 then Exit;
// Skip lines with current difference type
Kind := SynDiffEditLeft.Lines.Kind[Line];
while (Line < SynDiffEditLeft.Lines.Count - 1) and
(SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line);
if SynDiffEditLeft.Lines.Kind[Line] = ckNone then
if actBinaryCompare.Checked then
begin
// Skip unmodified lines
Kind := ckNone;
if BinaryDiffIndex < BinaryDiffList.Count - 1 then
begin
BinaryDiffIndex:= BinaryDiffIndex + 1;
BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
if not actKeepScrolling.Checked then
BinaryViewerRight.Position:= BinaryViewerLeft.Position;
end;
end
else begin
Line := SynDiffEditLeft.CaretY - 1;
if Line = SynDiffEditLeft.Lines.Count - 1 then Exit;
// Skip lines with current difference type
Kind := SynDiffEditLeft.Lines.Kind[Line];
while (Line < SynDiffEditLeft.Lines.Count - 1) and
(SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line);
end;
Inc(Line);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
if not actKeepScrolling.Checked then
begin
SynDiffEditRight.TopLine := Line;
SynDiffEditRight.CaretY := Line;
if SynDiffEditLeft.Lines.Kind[Line] = ckNone then
begin
// Skip unmodified lines
Kind := ckNone;
while (Line < SynDiffEditLeft.Lines.Count - 1) and
(SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line);
end;
Inc(Line);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
if not actKeepScrolling.Checked then
begin
SynDiffEditRight.TopLine := Line;
SynDiffEditRight.CaretY := Line;
end;
end;
end;
@ -793,27 +862,39 @@ var
Line: Integer;
Kind: TChangeKind;
begin
Line := SynDiffEditLeft.CaretY - 1;
if Line = 0 then Exit;
// Skip lines with current difference type
Kind := SynDiffEditLeft.Lines.Kind[Line];
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
if SynDiffEditLeft.Lines.Kind[Line] = ckNone then
if actBinaryCompare.Checked then
begin
// Skip unmodified lines
Kind := ckNone;
if BinaryDiffIndex > 0 then
begin
BinaryDiffIndex:= BinaryDiffIndex - 1;
BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
if not actKeepScrolling.Checked then
BinaryViewerRight.Position:= BinaryViewerLeft.Position;
end;
end
else begin
Line := SynDiffEditLeft.CaretY - 1;
if Line = 0 then Exit;
// Skip lines with current difference type
Kind := SynDiffEditLeft.Lines.Kind[Line];
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
end;
// Find top line of previous difference
Kind:= SynDiffEditLeft.Lines.Kind[Line];
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
if (Line <> 0) then Inc(Line, 2);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
if not actKeepScrolling.Checked then
begin
SynDiffEditRight.TopLine := Line;
SynDiffEditRight.CaretY := Line;
if SynDiffEditLeft.Lines.Kind[Line] = ckNone then
begin
// Skip unmodified lines
Kind := ckNone;
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
end;
// Find top line of previous difference
Kind:= SynDiffEditLeft.Lines.Kind[Line];
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
if (Line <> 0) then Inc(Line, 2);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
if not actKeepScrolling.Checked then
begin
SynDiffEditRight.TopLine := Line;
SynDiffEditRight.CaretY := Line;
end;
end;
end;

View file

@ -25,6 +25,23 @@ type
property SecondViewer: TBinaryDiffViewer read FSecondViewer write FSecondViewer;
end;
{ TBinaryCompare }
TBinaryCompare = class(TThread)
private
FFirst,
FSecond: PByte;
FFirstSize,
FSecondSize: PtrUInt;
FResult: TFPList;
FOnFinish: TThreadMethod;
protected
procedure Execute; override;
public
constructor Create(First, Second: PByte; FirstSize, SecondSize: PtrUInt; Result: TFPList);
property OnFinish: TThreadMethod read FOnFinish write FOnFinish;
end;
implementation
uses
@ -131,5 +148,35 @@ begin
ViewerMode:= vmHex;
end;
{ TBinaryCompare }
procedure TBinaryCompare.Execute;
var
Position: PtrInt = 0;
begin
FResult.Clear;
while (Terminated = False) and (Position < FFirstSize) and (Position < FSecondSize) do
begin
if not CompareMem(FFirst + Position, FSecond + Position, cHexWidth) then
begin
FResult.Add(Pointer(Position));
end;
Position:= Position + cHexWidth;
end;
if Assigned(FOnFinish) then Synchronize(FOnFinish);
end;
constructor TBinaryCompare.Create(First, Second: PByte; FirstSize,
SecondSize: PtrUInt; Result: TFPList);
begin
FFirst:= First;
FSecond:= Second;
FFirstSize:= FirstSize;
FSecondSize:= SecondSize;
FResult:= Result;
inherited Create(True);
FreeOnTerminate:= True;
end;
end.