Subversion Repositories indexer_suite

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 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.