
unit IdenticalFiles;

{$MODE DELPHI}

interface

uses
  SysUtils;

(* Différentes fonctions permettant de savoir si deux fichiers sont identiques. *)

type
  TComparisonMode = (
    cmBlockRead,
    cmFileStream,
    cmMemoryStream,
    cmMD5
  );

function CompareFiles(const AFile1, AFile2: TFileName; const AComparisonMode: TComparisonMode = cmBlockRead): boolean;

implementation

uses
  Classes, MD5;

const
  CKB = $400;
  CMB = $100000;
  CBlockSize = CMB;

function Compare1(const AFile1, AFile2: TFileName): boolean;
var
  f, g: file of byte;
  a, b: array[1..CBlockSize] of byte;
  n, o: integer;
  i: integer;
begin
  result := FALSE;
  AssignFile(f, AFile1);
  AssignFile(g, AFile2);
  {$I-}
  Reset(f, 1);
  if IOResult = 0 then
  begin
    Reset(g, 1);
    if IOResult = 0 then
      result := TRUE
    else
      CloseFile(f);
  end;
  {$I+}
  if not result then
    Exit;
  result := FileSize(f) = FileSize(g);
  if not result then
  begin
    CloseFile(f);
    CloseFile(g);
    Exit;
  end;
  repeat
    BlockRead(f, a, CBlockSize, n);
    BlockRead(g, b, CBlockSize, o);
    if n = o then
    begin
      i := Low(a);
      while result and (i <= n) do
      begin
        result := a[i] = b[i];
        Inc(i);
      end;
    end else
      result := FALSE;
  until (n < CBlockSize) or not result;
  CloseFile(f);
  CloseFile(g);
end;

function Compare2(const AFile1, AFile2: TFileName): boolean;
var
  s, t: TFileStream;
  n, o: integer;
  a, b: array[1..CBlockSize] of byte;
begin
  result := FALSE;
  if not (FileExists(AFile1) and FileExists(AFile2)) then
    Exit;
  s := TFileStream.Create(AFile1, fmOpenRead or fmShareDenyWrite);
  try
    t := TFileStream.Create(AFile2, fmOpenRead or fmShareDenyWrite);
    try
      if s.Size = t.Size then
      begin
        while s.Position < s.Size do
        begin
          n := s.Read(a[1], CBlockSize);
          o := t.Read(b[1], CBlockSize);
          if (n <> o) or not CompareMem(@a[1], @b[1], n) then
            Exit;
        end;
        result := TRUE;
      end;
    finally
      t.Free;
    end;
  finally
    s.Free;
  end;
end;

function Compare3(const AFile1, AFile2: TFileName): boolean;
var
  s, t: TMemoryStream;
begin
  result := FileExists(AFile1) and FileExists(AFile2);
  if result then
  begin
    s := TMemoryStream.Create;
    try
      t := TMemoryStream.Create;
      try
        s.LoadFromFile(AFile1);
        t.LoadFromFile(AFile2);
        result := s.Size = t.Size;
        if result then
          begin
            s.Position := 0;
            t.Position := 0;
            result := CompareMem(s.Memory, t.Memory, s.Size);
          end;
      finally
        t.Free;
      end;
    finally
      s.Free;
    end;
  end;
end;

function Compare4(const AFile1, AFile2: TFileName): boolean;
begin
  result := FALSE;
  if FileExists(AFile1) and FileExists(AFile2) then
    result := MD5Print(MD5File(AFile1)) = MD5Print(MD5File(AFile2));
end;

function CompareFiles(const AFile1, AFile2: TFileName; const AComparisonMode: TComparisonMode): boolean;
type
  TCompareFunction = function(const AFile1, AFile2: TFileName): boolean;
const
  CFunction: array[TComparisonMode] of TCompareFunction = (
    Compare1,
    Compare2,
    Compare3,
    Compare4
  );
begin
  result := CFunction[AComparisonMode](AFile1, AFile2);
end;

end.
