unit CheckThread; { Martin Harvey 30/5/2000 } interface uses Classes, Windows, ChecksumList, SysUtils; type TState = (sGetCurrentCRCs, sBuildFileList, sRemoveCRCs, sCheckFile, sDone); TStateReturn = (rvOK, rvFail1, rvFail2); TActionFunc = function: TStateReturn of object; TStateActions = array[TState] of TActionFunc; TNextStates = array[TState, TStateReturn] of TState; TCheckThread = class(TThread) private FStartDir: string; FCurrentState: TState; FActionFuncs: TStateActions; FNextStates: TNextStates; FInternalFileList: TStringList; FExternalFileList: TStringList; FExternalCRCList: TStringList; FCheckList: TChecksumList; FFileToProcess: integer; protected procedure InitActionFuncs; procedure InitNextStates; function GetCurrentCRCs: TStateReturn; function BuildFileList: TStateReturn; function RemoveCRCs: TStateReturn; function CheckFile: TStateReturn; procedure Execute; override; public constructor Create(CreateSuspended: boolean); destructor Destroy; override; property StartDir: string read FStartDir write FStartDir; property CheckList: TChecksumList read FCheckList write FCheckList; end; implementation { TCheckThread } {(*} {Prettyprinter auto-formatting off} const BaseStateTransitions:TNextStates = ( {rvOK} {rvFail1} {rvFail2} {sGetCurrentCRCs } ( sBuildFileList, sDone, sDone ), {sBuildFileList } ( sRemoveCRCs, sDone, sDone ), {sRemoveCRCs } ( sCheckFile, sDone, sDone ), {sCheckFile } ( sCheckFile, sGetCurrentCRCs, sDone ), {sDone } ( sDone, sDone, sDone )); {*)}{Prettyprinter auto-formatting on} procedure TCheckThread.InitActionFuncs; begin FActionFuncs[sGetCurrentCRCs] := GetCurrentCRCs; FActionFuncs[sBuildFileList] := BuildFileList; FActionFuncs[sRemoveCRCs] := RemoveCRCs; FActionFuncs[sCheckFile] := CheckFile; end; procedure TCheckThread.InitNextStates; begin FNextStates := BaseStateTransitions; end; function TCheckThread.GetCurrentCRCs: TStateReturn; begin FExternalFileList.Free; FExternalFileList := nil; FExternalCRCList.Free; FExternalCRCList := nil; FExternalFileList := FCheckList.GetFileList; FExternalCRCList := FCheckList.GetChecksumList; result := rvOK; end; function TCheckThread.BuildFileList: TStateReturn; var FindRet: integer; SearchRec: TSearchRec; begin FInternalFileList.Clear; FindRet := FindFirst(StartDir + '*.*', faAnyFile and not faDirectory, SearchRec); if FindRet <> 0 then result := rvFail1 else begin while FindRet = 0 do begin { Found a file.} FInternalFileList.Add(SearchRec.Name); FindRet := FindNext(SearchRec); end; result := rvOK; end; FindClose(SearchRec); FFileToProcess := 0; end; function TCheckThread.RemoveCRCs: TStateReturn; var iter: integer; dummy: integer; begin FInternalFileList.Sort; FExternalFileList.Sort; if FExternalFileList.Count > 0 then begin for iter := 0 to FExternalFileList.Count - 1 do begin if not FInternalFileList.Find(FExternalFileList[iter], dummy) then FCheckList.RemoveChecksum(FExternalFileList[iter]); end; end; result := rvOK; end; function TCheckThread.CheckFile: TStateReturn; var FileData: TFileStream; MemImage: TMemoryStream; Data: byte; Sum: integer; iter: integer; begin if FFileToProcess >= FInternalFileList.Count then begin result := rvFail1; exit; end; Sum := 0; FileData := nil; MemImage := nil; try FileData := TFileStream.Create(StartDir + FInternalFileList[FFileToProcess], fmOpenRead or fmShareDenyWrite); FileData.Seek(0, soFromBeginning); MemImage := TMemoryStream.Create; MemImage.CopyFrom(FileData, FileData.Size); MemImage.Seek(0, soFromBeginning); for iter := 1 to FileData.Size do begin MemImage.ReadBuffer(Data, sizeof(Data)); Inc(Sum, Data); end; FileData.Free; MemImage.Free; if (FCheckList.GetChecksum(FInternalFileList[FFileToProcess]) <> Sum) then FCheckList.SetChecksum(FInternalFileList[FFileTOProcess], Sum); except on EStreamError do begin FileData.Free; MemImage.Free; end; end; Inc(FFileToProcess); result := rvOK; end; procedure TCheckThread.Execute; begin SetThreadPriority(Handle, THREAD_PRIORITY_IDLE); while not (Terminated or (FCurrentState = sDone)) do FCurrentState := FNextStates[FCurrentState, FActionFuncs[FCurrentState]]; end; constructor TCheckThread.Create(CreateSuspended: boolean); begin inherited Create(CreateSuspended); InitActionFuncs; InitNextStates; FInternalFileList := TStringList.Create; end; destructor TCheckThread.Destroy; begin FInternalFileList.Free; FExternalFileList.Free; FExternalCRCList.Free; inherited Destroy; end; end.