// HashCon.cpp #include "StdAfx.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/ErrorMsg.h" #include "ConsoleClose.h" #include "HashCon.h" static const wchar_t *kEmptyFileAlias = L"[Content]"; static const char *kScanningMessage = "Scanning"; HRESULT CHashCallbackConsole::CheckBreak() { return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; } HRESULT CHashCallbackConsole::StartScanning() { (*OutStream) << kScanningMessage; return CheckBreak(); } HRESULT CHashCallbackConsole::ScanProgress(UInt64 /* numFolders */, UInt64 /* numFiles */, UInt64 /* totalSize */, const wchar_t * /* path */, bool /* isDir */) { return CheckBreak(); } HRESULT CHashCallbackConsole::CanNotFindError(const wchar_t *name, DWORD systemError) { return CanNotFindError_Base(name, systemError); } HRESULT CHashCallbackConsole::FinishScanning() { (*OutStream) << endl << endl; return CheckBreak(); } HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */) { return CheckBreak(); } HRESULT CHashCallbackConsole::SetTotal(UInt64 size) { if (EnablePercents) m_PercentPrinter.SetTotal(size); return CheckBreak(); } HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue) { if (completeValue && EnablePercents) { m_PercentPrinter.SetRatio(*completeValue); m_PercentPrinter.PrintRatio(); } return CheckBreak(); } static void AddMinuses(AString &s, unsigned num) { for (unsigned i = 0; i < num; i++) s += '-'; } static void SetSpaces(char *s, int num) { for (int i = 0; i < num; i++) s[i] = ' '; } static void SetSpacesAndNul(char *s, int num) { SetSpaces(s, num); s[num] = 0; } static void AddSpaces(UString &s, int num) { for (int i = 0; i < num; i++) s += ' '; } static const int kSizeField_Len = 13; static const int kNameField_Len = 12; static unsigned GetColumnWidth(unsigned digestSize) { unsigned width = digestSize * 2; const unsigned kMinColumnWidth = 8; return width < kMinColumnWidth ? kMinColumnWidth: width; } void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers) { AString s; for (unsigned i = 0; i < hashers.Size(); i++) { const CHasherState &h = hashers[i]; AddMinuses(s, GetColumnWidth(h.DigestSize)); s += ' '; } AddMinuses(s, kSizeField_Len); s += " "; AddMinuses(s, kNameField_Len); m_PercentPrinter.PrintString(s); m_PercentPrinter.PrintNewLine(); } HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb) { UString s; FOR_VECTOR (i, hb.Hashers) { const CHasherState &h = hb.Hashers[i]; s += h.Name; AddSpaces(s, (int)GetColumnWidth(h.DigestSize) - h.Name.Len() + 1); } UString s2 = L"Size"; AddSpaces(s, kSizeField_Len - s2.Len()); s += s2; s += L" "; s += L"Name"; m_PercentPrinter.PrintString(s); m_PercentPrinter.PrintNewLine(); PrintSeparatorLine(hb.Hashers); return CheckBreak(); } HRESULT CHashCallbackConsole::OpenFileError(const wchar_t *name, DWORD systemError) { FailedCodes.Add(systemError); FailedFiles.Add(name); // if (systemError == ERROR_SHARING_VIOLATION) { m_PercentPrinter.PrintString(name); m_PercentPrinter.PrintString(": WARNING: "); m_PercentPrinter.PrintString(NWindows::NError::MyFormatMessage(systemError)); return S_FALSE; } // return systemError; } HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool /* isFolder */) { m_FileName = name; return CheckBreak(); } void CHashCallbackConsole::PrintResultLine(UInt64 fileSize, const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash) { FOR_VECTOR (i, hashers) { const CHasherState &h = hashers[i]; char s[k_HashCalc_DigestSize_Max * 2 + 64]; s[0] = 0; if (showHash) AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize); SetSpacesAndNul(s + strlen(s), (int)GetColumnWidth(h.DigestSize) - (int)strlen(s) + 1); m_PercentPrinter.PrintString(s); } char s[64]; s[0] = 0; char *p = s; if (showHash && fileSize != 0) { p = s + 32; ConvertUInt64ToString(fileSize, p); int numSpaces = kSizeField_Len - (int)strlen(p); if (numSpaces > 0) { p -= numSpaces; SetSpaces(p, numSpaces); } } else SetSpacesAndNul(s, kSizeField_Len - (int)strlen(s)); unsigned len = (unsigned)strlen(p); p[len] = ' '; p[len + 1] = ' '; p[len + 2] = 0; m_PercentPrinter.PrintString(p); } HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) { PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash); if (m_FileName.IsEmpty()) m_PercentPrinter.PrintString(kEmptyFileAlias); else m_PercentPrinter.PrintString(m_FileName); m_PercentPrinter.PrintNewLine(); return S_OK; } static const char *k_DigestTitles[] = { " :" , " for data: " , " for data and names: " , " for streams and names: " }; static void PrintSum(CStdOutStream &p, const CHasherState &h, unsigned digestIndex) { char s[k_HashCalc_DigestSize_Max * 2 + 64]; UString name = h.Name; AddSpaces(name, 6 - (int)name.Len()); p << name; p << k_DigestTitles[digestIndex]; s[0] = 0; AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize); p << s; p << "\n"; } void PrintHashStat(CStdOutStream &p, const CHashBundle &hb) { FOR_VECTOR (i, hb.Hashers) { const CHasherState &h = hb.Hashers[i]; p << "\n"; PrintSum(p, h, k_HashCalc_Index_DataSum); if (hb.NumFiles != 1 || hb.NumDirs != 0) PrintSum(p, h, k_HashCalc_Index_NamesSum); if (hb.NumAltStreams != 0) PrintSum(p, h, k_HashCalc_Index_StreamsSum); } } void CHashCallbackConsole::PrintProperty(const char *name, UInt64 value) { char s[32]; s[0] = ':'; s[1] = ' '; ConvertUInt64ToString(value, s + 2); m_PercentPrinter.PrintString(name); m_PercentPrinter.PrintString(s); m_PercentPrinter.PrintNewLine(); } HRESULT CHashCallbackConsole::AfterLastFile(const CHashBundle &hb) { PrintSeparatorLine(hb.Hashers); PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true); m_PercentPrinter.PrintNewLine(); m_PercentPrinter.PrintNewLine(); if (hb.NumFiles != 1 || hb.NumDirs != 0) { if (hb.NumDirs != 0) PrintProperty("Folders", hb.NumDirs); PrintProperty("Files", hb.NumFiles); } PrintProperty("Size", hb.FilesSize); if (hb.NumAltStreams != 0) { PrintProperty("AltStreams", hb.NumAltStreams); PrintProperty("AltStreams size", hb.AltStreamsSize); } PrintHashStat(*m_PercentPrinter.OutStream, hb); m_PercentPrinter.PrintNewLine(); return S_OK; }