Subversion Repositories indexer_suite

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit RedundancyForm;
  2.  
  3. interface
  4.  
  5. uses
  6.   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  7.   System.Classes, Vcl.Graphics, AdoDb,
  8.   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Gauges;
  9.  
  10. type
  11.   TfrmRedundancy = class(TForm)
  12.     Button1: TButton;
  13.     Memo1: TMemo;
  14.     Gauge1: TGauge;
  15.     Edit1: TEdit;
  16.     Label1: TLabel;
  17.     Label2: TLabel;
  18.     ComboBox1: TComboBox;
  19.     Label3: TLabel;
  20.     Label4: TLabel;
  21.     procedure Button1Click(Sender: TObject);
  22.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  23.     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  24.     procedure FormShow(Sender: TObject);
  25.   private
  26.     procedure Mode2Rec(StartDir: string; const FileMask: string;
  27.       var cntRedundant: integer; var cntUnique: integer);
  28.   protected
  29.     StopRequest: Boolean;
  30.     procedure EnableDisableControls(v: Boolean);
  31.     function TableName: string;
  32.     function conn: TAdoConnection;
  33.   end;
  34.  
  35. implementation
  36.  
  37. {$R *.dfm}
  38.  
  39. uses
  40.   DB, AdoConnHelper, IdHashMessageDigest, idHash, MainForm, IniFiles;
  41.  
  42. function MD5File(const FileName: string): string;
  43. var
  44.   IdMD5: TIdHashMessageDigest5;
  45.   FS: TFileStream;
  46. begin
  47.   IdMD5 := TIdHashMessageDigest5.Create;
  48.   FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  49.   try
  50. {$IFDEF UNICODE} // I actually do not know at which version of Delphi/Indy, this has changed.
  51.     Result := IdMD5.HashStreamAsHex(FS);
  52. {$ELSE}
  53.     Result := IdMD5.AsHex(IdMD5.HashValue(FS));
  54. {$ENDIF}
  55.   finally
  56.     FS.Free;
  57.     IdMD5.Free;
  58.   end;
  59. end;
  60.  
  61. procedure TfrmRedundancy.Mode2Rec(StartDir: string; const FileMask: string;
  62.   var cntRedundant: integer; var cntUnique: integer);
  63.  
  64.   procedure CheckFile(aFilename: string);
  65.   var
  66.     md5: string;
  67.   begin
  68.     try
  69.       Label4.Caption := aFilename;
  70.       md5 := MD5File(aFilename);
  71.       if conn.GetScalar('select count(*) from ' + TableName +
  72.         ' where md5hash = ' + conn.SQLStringEscape(md5)) = 0 then
  73.       begin
  74.         Memo1.Lines.Add(aFilename);
  75.         Inc(cntUnique);
  76.       end
  77.       else
  78.       begin
  79.         Inc(cntRedundant);
  80.       end;
  81.     except
  82.       on E: Exception do
  83.       begin
  84.         Memo1.Lines.Add(Format('Error: Cannot process %s : %s',
  85.           [aFilename, E.Message]))
  86.       end;
  87.     end;
  88.   end;
  89.  
  90. var
  91.   SR: TSearchRec;
  92.   DirList: TStrings;
  93.   IsFound: Boolean;
  94.   i: integer;
  95. begin
  96.   StartDir := IncludeTrailingPathDelimiter(StartDir);
  97.  
  98.   i := 0;
  99.   IsFound := FindFirst(StartDir + FileMask, faAnyFile - faDirectory, SR) = 0;
  100.   try
  101.     while IsFound do
  102.     begin
  103.       Inc(i);
  104.       Application.ProcessMessages;
  105.       if Application.Terminated or StopRequest then
  106.         Abort;
  107.  
  108.       CheckFile(StartDir + SR.Name);
  109.       IsFound := FindNext(SR) = 0;
  110.     end;
  111.   finally
  112.     FindClose(SR);
  113.   end;
  114.  
  115.   // Build a list of subdirectories
  116.   DirList := TStringList.Create;
  117.   try
  118.     IsFound := FindFirst(StartDir + '*', faDirectory, SR) = 0;
  119.     try
  120.       while IsFound do
  121.       begin
  122.         if (SR.Name <> '.') and (SR.Name <> '..') then
  123.         begin
  124.           Application.ProcessMessages;
  125.           if Application.Terminated or StopRequest then
  126.             Abort;
  127.  
  128.           DirList.Add(StartDir + SR.Name);
  129.         end;
  130.         IsFound := FindNext(SR) = 0;
  131.       end;
  132.     finally
  133.       FindClose(SR);
  134.     end;
  135.  
  136.     // Scan the list of subdirectories
  137.     for i := 0 to DirList.Count - 1 do
  138.     begin
  139.       try
  140.         Mode2Rec(DirList[i], FileMask, cntRedundant, cntUnique);
  141.       except
  142.         on E: Exception do
  143.         begin
  144.           if E is EAbort then
  145.             Abort;
  146.           Memo1.Lines.Add('Unexpected error at directory ' + DirList[i] + ': ' +
  147.             E.Message);
  148.         end;
  149.       end;
  150.     end;
  151.   finally
  152.     DirList.Free;
  153.   end;
  154. end;
  155.  
  156. function TfrmRedundancy.TableName: string;
  157. begin
  158.   result := frmMain.TableName;
  159. end;
  160.  
  161. procedure TfrmRedundancy.Button1Click(Sender: TObject);
  162. var
  163.   q: TADODataSet;
  164.   fMD5: TField;
  165.   fFilename: TField;
  166.   dirMask: string;
  167.   cntRedundant: integer;
  168.   cntUnique: integer;
  169. begin
  170.   EnableDisableControls(False);
  171.   if ComboBox1.ItemIndex = 1 then
  172.     Gauge1.Visible := False;
  173.   Memo1.Lines.Clear;
  174.   try
  175. {$REGION 'Mode 1'}
  176.     if ComboBox1.ItemIndex = 0 then
  177.     begin
  178.       dirMask := IncludeTrailingPathDelimiter(Edit1.Text) + '%';
  179.       q := conn.GetTable
  180.         ('select filename, md5hash from '+TableName+' where filename like ' +
  181.         conn.SQLStringEscape(dirMask) + ' order by filename');
  182.       try
  183.         Gauge1.MinValue := 0;
  184.         Gauge1.MaxValue := q.RecordCount;
  185.         Gauge1.Progress := 0;
  186.         cntRedundant := 0;
  187.         cntUnique := 0;
  188.         fMD5 := q.FieldByName('md5hash');
  189.         fFilename := q.FieldByName('filename');
  190.         while not q.Eof do
  191.         begin
  192.           if conn.GetScalar('select count(*) from '+TableName+' where md5hash = ' +
  193.             conn.SQLStringEscape(fMD5.AsString) + ' and filename not like ' +
  194.             conn.SQLStringEscape(dirMask)) = 0 then
  195.           begin
  196.             Memo1.Lines.Add(fFilename.AsString);
  197.             Inc(cntUnique);
  198.           end
  199.           else
  200.           begin
  201.             Inc(cntRedundant);
  202.           end;
  203.           Gauge1.Progress := Gauge1.Progress + 1;
  204.           Application.ProcessMessages;
  205.           if Application.Terminated then
  206.             Abort;
  207.           q.Next;
  208.         end;
  209.       finally
  210.         q.Free;
  211.       end;
  212.     end;
  213. {$ENDREGION}
  214. {$REGION 'Mode 2'}
  215.     if ComboBox1.ItemIndex = 1 then
  216.     begin
  217.       cntRedundant := 0;
  218.       cntUnique := 0;
  219.       Mode2Rec(Edit1.Text, '*', cntRedundant, cntUnique);
  220.     end;
  221. {$ENDREGION}
  222.     if (cntRedundant = 0) and (cntUnique = 0) then
  223.       raise Exception.Create('No files found. Is the string correct?')
  224.     else
  225.       ShowMessageFmt('Done. %d files are redundant. %d are unique.',
  226.         [cntRedundant, cntUnique]);
  227.  
  228.     if ComboBox1.ItemIndex = 0 then
  229.     begin
  230.       ShowMessage
  231.         ('Attention: Only check 1 directory at a time, then delete redundant files, then re-index and only then continue with checking the redundancy of the any other directory.');
  232.     end;
  233.   finally
  234.     EnableDisableControls(True);
  235.     Gauge1.Progress := 0;
  236.     Gauge1.Visible := True;
  237.     Label4.Caption := '';
  238.   end;
  239. end;
  240.  
  241. function TfrmRedundancy.conn: TAdoConnection;
  242. begin
  243.   Result := frmMain.AdoConnection1;
  244. end;
  245.  
  246. procedure TfrmRedundancy.EnableDisableControls(v: Boolean);
  247. begin
  248.   Edit1.Enabled := v;
  249.   Button1.Enabled := v;
  250.   ComboBox1.Enabled := v;
  251. end;
  252.  
  253. procedure TfrmRedundancy.FormClose(Sender: TObject; var Action: TCloseAction);
  254. begin
  255.   Action := caFree;
  256. end;
  257.  
  258. procedure TfrmRedundancy.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  259. begin
  260.   StopRequest := True;
  261. end;
  262.  
  263. procedure TfrmRedundancy.FormShow(Sender: TObject);
  264. var
  265.   ini: TMemIniFile;
  266. begin
  267.   ini := frmMain.ini;
  268.   Edit1.Text := ini.ReadString('RedundancyFinder', 'DefaultDir', '');
  269.   ComboBox1.ItemIndex := ini.ReadInteger('RedundancyFinder', 'DefaultMode', 1)-1;
  270. end;
  271.  
  272. end.
  273.