Subversion Repositories checksum-tools

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
unit Unit1;
2
 
3
interface
4
 
5
uses
6
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
7
  System.Classes, Vcl.Graphics,
8
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
9
 
10
type
11
  TSeverity = (seOK, seWarning, seCritical);
12
 
13
  TForm1 = class(TForm)
14
    Button1: TButton;
15
    Memo1: TMemo;
16
    cbVerbose: TCheckBox;
17
    LabeledEdit1: TLabeledEdit;
18
    cbWarnChecksumFileMissing: TCheckBox;
19
    cbWarningMissingChecksumFileEntry: TCheckBox;
20
    cbWarnVanishedFile: TCheckBox;
21
    cbWarnChecksumMismatch: TCheckBox;
22
    Label1: TLabel;
23
    RadioGroup1: TRadioGroup;
24
    procedure Button1Click(Sender: TObject);
25
    procedure FormShow(Sender: TObject);
26
  private
27
    CheckSumFileCount: integer;
28
    function CheckDirectory(ADirectory: string; recursive: boolean): TSeverity;
29
    function VerifyChecksumFile(aChecksumFile: string): TSeverity;
30
    function GetChecksumSafe(const filename: string): string;
31
  end;
32
 
33
var
34
  Form1: TForm1;
35
 
36
implementation
37
 
38
{$R *.dfm}
39
 
40
uses
41
  MD5, SFV, Common;
42
 
43
const
44
  DUMMY_FILE = 'DUMMY.$$$';
45
 
46
procedure TForm1.Button1Click(Sender: TObject);
47
var
48
  sev: TSeverity;
49
begin
50
  Memo1.Clear;
51
  if not DirectoryExists(LabeledEdit1.Text) then
52
  begin
53
    showmessage('Directory does not exist');
54
    exit;
55
  end;
56
  Application.ProcessMessages;
57
  CheckSumFileCount := 0;
58
  sev := CheckDirectory(LabeledEdit1.Text, true);
59
  Beep;
60
  case sev of
61
    seOK:
62
      showmessage('OK');
63
    seWarning:
64
      showmessage('Warning');
65
    seCritical:
66
      showmessage('Critical');
67
  end;
68
  Caption := Format('Done. Checked %d checksum files.', [CheckSumFileCount]);
69
end;
70
 
71
function SevMax(a, b: TSeverity): TSeverity;
72
begin
73
  if Ord(a) > Ord(b) then
74
    Result := a
75
  else
76
    Result := b;
77
end;
78
 
79
function TForm1.VerifyChecksumFile(aChecksumFile: string): TSeverity;
80
var
81
  slFile: TStringList;
82
  i: integer;
83
  originalFilename: string;
84
  expectedChecksum: string;
85
  IsFound: boolean;
86
  SR: TSearchRec;
87
  fullfilename: string;
88
  ADirectory: string;
89
  originalFilenameFull: string;
90
begin
17 daniel-mar 91
  if Copy(aChecksumFile, 2, 1) = ':' then aChecksumFile := '\\?\' + aChecksumFile; // To allow long filenames
92
 
2 daniel-mar 93
  if ExtractFileName(aChecksumFile) <> DUMMY_FILE then
94
  begin
95
    Inc(CheckSumFileCount);
96
  end;
97
 
98
  if cbVerbose.Checked then
99
  begin
17 daniel-mar 100
    Form1.Memo1.Lines.Add('Check: ' + StringReplace(aChecksumFile,'\\?\','',[]));
2 daniel-mar 101
  end;
102
 
103
  Result := seOK;
104
  ADirectory := IncludeTrailingPathDelimiter(ExtractFilePath(aChecksumFile));
105
 
106
  try
107
    slFile := TStringList.Create;
108
    try
109
      slFile.CaseSensitive := false;
110
      slFile.OwnsObjects := true;
111
 
112
      if radiogroup1.itemindex = 0 then
113
        SFVFileToStringList(aChecksumFile, slFile)
114
      else
115
        MD5FileToStringList(aChecksumFile, slFile);
116
      // TODO: If multiple checksum files => put them together into a single array (beware conflicts!)
117
 
118
      // 1. Check existing entries in the checksum file
119
 
120
      for i := 0 to slFile.Count - 1 do
121
      begin
122
        originalFilename := slFile.Strings[i];
123
        expectedChecksum := TChecksum(slFile.Objects[i]).checksum;
124
 
125
        originalFilenameFull := ADirectory + originalFilename;
126
        if not FileExists(originalFilenameFull) then
127
        begin
128
          if cbWarnVanishedFile.Checked then
129
          begin
17 daniel-mar 130
            Form1.Memo1.Lines.Add('FILE VANISHED: ' + StringReplace(originalFilenameFull,'\\?\','',[]));
2 daniel-mar 131
            Result := SevMax(Result, seCritical);
132
          end;
133
        end
134
        else if LowerCase(GetChecksumSafe(originalFilenameFull))
135
          = LowerCase(expectedChecksum) then
136
        begin
137
          if cbVerbose.Checked then
138
          begin
17 daniel-mar 139
            Form1.Memo1.Lines.Add('OK: ' + StringReplace(originalFilenameFull,'\\?\','',[]) + ' = ' +
2 daniel-mar 140
              expectedChecksum);
141
          end;
142
          Result := SevMax(Result, seOK);
143
        end
144
        else
145
        begin
146
          if cbWarnChecksumMismatch.Checked then
147
          begin
17 daniel-mar 148
            Form1.Memo1.Lines.Add('CHECKSUM MISMATCH: ' + StringReplace(originalFilenameFull,'\\?\','',[]) +
2 daniel-mar 149
              ' <> ' + expectedChecksum);
150
            Result := SevMax(Result, seCritical);
151
          end;
152
        end;
153
      end;
154
 
155
      // 2. Checking for entries which are NOT in the checksum file
156
 
157
      IsFound := FindFirst(ADirectory + '*', faAnyFile - faDirectory, SR) = 0;
158
      while IsFound do
159
      begin
160
        fullfilename := ADirectory + SR.Name;
161
        if (LowerCase(ExtractFileExt(fullfilename)) <> '.md5') and
162
           (LowerCase(ExtractFileExt(fullfilename)) <> '.sfv') and
163
           (LowerCase(ExtractFileName(fullfilename)) <> 'thumbs.db') then
164
        begin
165
          if slFile.IndexOf(SR.Name) = -1 then //if slFile.Values[SR.Name] = '' then
166
          begin
167
            if ExtractFileName(aChecksumFile) = DUMMY_FILE then
168
            begin
169
              if cbWarnChecksumFileMissing.Checked then
170
              begin
171
                Form1.Memo1.Lines.Add('NEW FILE WITHOUT CHECKSUM FILE: ' +
17 daniel-mar 172
                  StringReplace(fullfilename,'\\?\','',[]));
2 daniel-mar 173
                Result := SevMax(Result, seWarning);
174
              end;
175
            end
176
            else
177
            begin
178
              if cbWarningMissingChecksumFileEntry.Checked then
179
              begin
180
                Form1.Memo1.Lines.Add('NEW FILE WITHOUT CHECKSUM ENTRY: ' +
17 daniel-mar 181
                  StringReplace(fullfilename,'\\?\','',[]));
2 daniel-mar 182
                Result := SevMax(Result, seWarning);
183
              end;
184
            end;
185
          end;
186
        end;
187
        IsFound := FindNext(SR) = 0;
188
      end;
189
      FindClose(SR);
190
    finally
191
      slFile.Free;
192
    end;
193
  except
194
    on E: Exception do
195
    begin
196
      Memo1.Lines.Add('Invalid checksum file: ' + aChecksumFile + ' : ' + E.Message);
197
      Result := seCritical;
198
    end;
199
  end;
200
end;
201
 
202
function TForm1.CheckDirectory(ADirectory: string; recursive: boolean)
203
  : TSeverity;
204
var
205
  IsFound: boolean;
206
  SR: TSearchRec;
207
  fullfilename: string;
208
begin
209
  Caption := ADirectory;
210
  Application.ProcessMessages;
211
  if Application.Terminated then Abort;
212
 
213
  Result := seOK;
214
  ADirectory := IncludeTrailingPathDelimiter(ADirectory);
215
 
216
  // Check checksum files
217
  if radiogroup1.itemindex = 0 then
218
    IsFound := FindFirst(ADirectory + '*.sfv', faAnyFile - faDirectory, SR) = 0
219
  else
220
    IsFound := FindFirst(ADirectory + '*.md5', faAnyFile - faDirectory, SR) = 0;
221
  if not IsFound then
222
  begin
223
    fullfilename := ADirectory + DUMMY_FILE; // virtual "empty" file
224
    Result := SevMax(Result, VerifyChecksumFile(fullfilename));
225
  end
226
  else
227
  begin
228
    while IsFound do
229
    begin
230
      fullfilename := ADirectory + SR.Name;
231
 
232
      Caption := fullfilename;
233
      Application.ProcessMessages;
234
      if Application.Terminated then Abort;
235
 
236
      Result := SevMax(Result, VerifyChecksumFile(fullfilename));
237
      IsFound := FindNext(SR) = 0;
238
    end;
239
  end;
240
  FindClose(SR);
241
 
242
  // Check other dirs
243
  if recursive then
244
  begin
245
    IsFound := FindFirst(ADirectory + '*', faAnyFile, SR) = 0;
246
    while IsFound do
247
    begin
248
      fullfilename := ADirectory + SR.Name;
249
      if DirectoryExists(fullfilename) and (SR.Name <> '.') and (SR.Name <> '..')
250
      then
251
      begin
252
        Result := SevMax(Result, CheckDirectory(fullfilename, recursive));
253
      end;
254
      IsFound := FindNext(SR) = 0;
255
    end;
256
    FindClose(SR);
257
  end;
258
end;
259
 
260
procedure TForm1.FormShow(Sender: TObject);
261
begin
262
  if ParamCount >= 1 then
263
  begin
264
    LabeledEdit1.Text := ParamStr(1);
265
  end;
266
end;
267
 
268
function TForm1.GetChecksumSafe(const filename: string): string;
269
begin
270
  Caption := filename;
271
  Application.ProcessMessages;
272
  if Application.Terminated then Abort;
273
 
274
  try
275
    if radiogroup1.itemindex = 0 then
276
      Result := CalcFileCRC32(filename)
277
    else
278
      Result := md5file(filename);
279
  except
280
    on E: Exception do
281
    begin
282
      Memo1.Lines.Add('Cannot read file ' + filename + ' : ' + E.Message);
283
      Result := 'ERROR';
284
    end;
285
  end;
286
end;
287
 
288
end.