Option Explicit Dim fso : Set fso = CreateObject( "Scripting.FileSystemObject" ) Dim fsu : Set fsu = DOpus.FSUtil Dim hashFiles : Set hashFiles = CreateObject( "Scripting.Dictionary" ) Dim hashData : Set hashData = CreateObject( "Scripting.Dictionary" ) Function OnInit( initData ) initData.name = "Hash" initData.version = "1.0" initData.copyright = "(c) 2016 Tenebrous" ' initData.url = "https://resource.dopus.com/viewforum.php?f=35" initData.desc = "Generates checksums.md5 and can validate files against it" initData.default_enable = true initData.min_version = "12.0" With initData.AddCommand() .name = "GenerateHashFile" .method = "OnCommandGenerateHash" .desc = "Generates a file with the hashes in for each selected file" .label = "GenerateHashFile" .template = "FILENAME/K,TYPE/K,FILES/M" End With With initData.AddColumn() .name = "HashMatch" .label = "Hash Match" .type = "" .method = "OnColumnHashMatch" .autogroup = true .autorefresh = true .justify = "left" .multicol = false End With End Function Function OnCommandGenerateHash( scriptCmdData ) Dim outputFile Dim outputPath Dim temp Dim hash Dim extension Dim fileList If scriptCmdData.func.args.got_arg.files Then Set fileList = scriptCmdData.func.args.files Else Set fileList = scriptCmdData.func.sourcetab.selected End If '' by default use md5 unless told otherwise hash = "md5" If scriptCmdData.func.args.got_arg.type Then If LCase(scriptCmdData.func.args.type) = "sha" Then hash = "sha" End If End If extension = HashExtension(hash) If scriptCmdData.func.args.got_arg.filename Then '' write to specified hash file outputFile = scriptCmdData.func.args.filename Set outputPath = DOpus.FSUtil.NewPath( outputFile ) If outputPath.test_parent Then outputPath.Parent End If Else '' no hash file specified, decide on filename If fileList.count = 1 Then '' only one file selected, write hash to selected filename with hash extension outputFile = fileList(0) & "." & extension Set outputPath = fsu.NewPath( outputFile ) If outputPath.test_parent Then outputPath.Parent End If Else '' multiple files selected, write hash to "checksum." with hash extension Set outputPath = scriptCmdData.func.command.source Set temp = fsu.NewPath(outputPath) temp.Add "checksums." & extension outputFile = CStr(temp) End If End If Dim progress : Set progress = scriptCmdData.func.command.Progress progress.Init scriptCmdData.func.sourcetab.lister, "Calculating hashes" With progress .owned = true .bytes = false .abort = true .pause = false .skip = false End With progress.Show progress.SetStatus "Counting files..." Dim outputStream : Set outputStream = fso.OpenTextFile( outputFile, 2, True ) Dim file Dim item For Each file in fileList Set item = fsu.GetItem( file ) If item.is_dir Then CountFolder file, progress Else progress.AddFiles 1 End If Next '' file progress.SetStatus "Calculating hashes..." For Each file in fileList Set item = fsu.GetItem( file ) If item.is_dir Then CalculateFolder outputStream, outputPath, file, progress, hash ElseIf CStr(item) <> outputFile Then progress.SetName CStr(file) CalculateFile outputStream, outputPath, file, progress, hash progress.StepFiles 1 End If Next '' file progress.Hide ClearCache scriptCmdData.func.command.RunCommand "Go REFRESH=all" Set outputStream = Nothing Set fso = Nothing End Function Function CountFolder( folderPath, progress ) Dim enumerator Dim item Set enumerator = fsu.ReadDir( folderPath, True ) While Not enumerator.complete Set item = enumerator.Next If Not item.is_dir Then progress.AddFiles 1 End If Wend enumerator.Close End Function Function CalculateFolder( outputStream, basePath, folderPath, progress, hash ) Dim enumerator Dim item Set enumerator = fsu.ReadDir( folderPath, True ) While Not enumerator.complete Set item = enumerator.Next If Not item.is_dir Then progress.SetName CStr(item) CalculateFile outputStream, basePath, item, progress, hash progress.StepFiles 1 End If Wend enumerator.Close End Function Function CalculateFile( outputStream, basePath, filename, progress, hash ) outputStream.WriteLine fsu.Hash( filename, hash ) & " *" & Mid( filename, Len(basePath) + 2 ) End Function Function OnColumnHashMatch( scriptColData ) On Error Resume Next If scriptColData.item.is_dir Then Exit Function End If If Err.Number <> 0 Then Exit Function End If Select Case LCase(scriptColData.item.ext) Case "." & HashExtension("md5") scriptColData.value = CompareAllHashes( CStr( scriptColData.item ), "md5" ) Exit Function Case "." & HashExtension("sha") scriptColData.value = CompareAllHashes( CStr( scriptColData.item ), "sha" ) Exit Function End Select On Error Goto 0 Dim result : result = "" result = CompareFileHash( "md5", scriptColData.item ) _ & " " _ & CompareFileHash( "sha", scriptColData.item ) scriptColData.value = Trim( result ) End Function Function CompareFileHash( hash, item ) Dim result Dim path : Set path = fsu.NewPath( item.path ) Dim hashFullPath '' firstly check for filename. in same folder Set hashFullPath = fsu.NewPath( path ) hashFullPath.Add item.name & "." & HashExtension(hash) If fsu.Exists( hashFullPath ) Then result = CompareHash( hashFullPath.pathpart, CStr(hashFullPath), CStr(item), hash ) Else '' now find checksums. in current or any parent folder Set hashFullPath = FindHashFileForPath( path, HashExtension(hash) ) If Not hashFullPath Is Nothing Then result = CompareHash( hashFullPath.pathpart, CStr(hashFullPath), CStr(item), hash ) End If End If CompareFileHash = result End Function Function FindHashFileForPath( path, extension ) Dim pathStr : pathStr = CStr( path ) Dim key : key = extension & "_" & pathStr If hashFiles.Exists( key ) Then Set FindHashFileForPath = hashFiles( key ) Exit Function End If Dim hashFullPath Set FindHashFileForPath = Nothing Do While True Set hashFullPath = fsu.NewPath( path ) hashFullPath.Add "checksums." & extension If fsu.Exists( hashFullPath ) Then Set FindHashFileForPath = hashFullPath Exit Do End If If path.test_parent <> True Then Exit Do End If path.Parent Loop hashFiles.Add key, FindHashFileForPath End Function Function GethashData( hashFilePathStr ) If hashData.Exists( hashFilePathStr ) Then Set GethashData = hashData( hashFilePathStr ) Exit Function End If Set GethashData = CreateObject( "SCripting.Dictionary" ) Dim inputStream : Set inputStream = fso.OpenTextFile( hashFilePathStr, 1 ) Dim line Dim parts While Not inputStream.AtEndOfStream line = Trim(inputStream.ReadLine) If line <> "" Then parts = Split( line, " *" ) If UBound( parts ) = 1 Then GethashData.Add parts(1), parts(0) End If End If Wend hashData.Add hashFilePathStr, GethashData End Function Function CompareHash( rootPath, checksumFilePath, itemPath, hash ) Dim relativePath : relativePath = mid( itemPath, len(rootPath)+2 ) Dim hashes : Set hashes = GethashData( checksumFilePath ) Dim previousHash Dim currentHash CompareHash = "" If hashes.Exists( relativePath ) Then previousHash = hashes( relativePath ) currentHash = fsu.Hash( itemPath, hash ) If previousHash = currentHash Then CompareHash = HashName(hash) + ":ok" Else CompareHash = HashName(hash) + ":error" End If End If End Function Function HashName(hash) Select Case hash Case "md5": HashName = "md5" Case "sha": HashName = "sha1" End Select End Function Function HashExtension(hash) Select Case hash Case "md5": HashExtension = "md5" Case "sha": HashExtension = "sha1" End Select End Function Function CompareAllHashes( checksumFile, hash ) Dim line Dim parts Dim previousHash Dim currentChecksum Dim filename Dim filenamePath Dim item Dim count : count = 0 Dim countOK : countOK = 0 Dim inputStream : Set inputStream = fso.OpenTextFile( checksumFile, 1 ) Dim inputPath : Set inputPath = fsu.NewPath( checksumFile ) inputPath.parent While Not inputStream.AtEndOfStream line = Trim(inputStream.ReadLine) If line <> "" Then parts = Split( line, " *" ) If UBound( parts ) = 1 Then count = count + 1 previousHash = parts(0) filename = parts(1) Set filenamePath = fsu.NewPath( inputPath ) filenamePath.Add filename currentChecksum = fsu.Hash( filenamePath, hash ) If previousHash = currentChecksum Then countOK = countOK + 1 End If End If End If Wend If countOK = count Then CompareAllHashes = HashName(hash) + ":ok (" & countOK & " / " & count & ")" Else CompareAllHashes = HashName(hash) + ":error (" & countOK & " / " & count & ")" End If End Function Function ClearCache() Set hashFiles = CreateObject( "Scripting.Dictionary" ) Set hashData = CreateObject( "Scripting.Dictionary" ) End Function