1// HashCon.cpp 2 3#include "StdAfx.h" 4 5#include "../../../Common/IntToString.h" 6#include "../../../Common/StringConvert.h" 7 8#include "../../../Windows/ErrorMsg.h" 9 10#include "ConsoleClose.h" 11#include "HashCon.h" 12 13static const wchar_t *kEmptyFileAlias = L"[Content]"; 14 15static const char *kScanningMessage = "Scanning"; 16 17HRESULT CHashCallbackConsole::CheckBreak() 18{ 19 return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; 20} 21 22HRESULT CHashCallbackConsole::StartScanning() 23{ 24 (*OutStream) << kScanningMessage; 25 return CheckBreak(); 26} 27 28HRESULT CHashCallbackConsole::ScanProgress(UInt64 /* numFolders */, UInt64 /* numFiles */, UInt64 /* totalSize */, const wchar_t * /* path */, bool /* isDir */) 29{ 30 return CheckBreak(); 31} 32 33HRESULT CHashCallbackConsole::CanNotFindError(const wchar_t *name, DWORD systemError) 34{ 35 return CanNotFindError_Base(name, systemError); 36} 37 38HRESULT CHashCallbackConsole::FinishScanning() 39{ 40 (*OutStream) << endl << endl; 41 return CheckBreak(); 42} 43 44HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */) 45{ 46 return CheckBreak(); 47} 48 49HRESULT CHashCallbackConsole::SetTotal(UInt64 size) 50{ 51 if (EnablePercents) 52 m_PercentPrinter.SetTotal(size); 53 return CheckBreak(); 54} 55 56HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue) 57{ 58 if (completeValue && EnablePercents) 59 { 60 m_PercentPrinter.SetRatio(*completeValue); 61 m_PercentPrinter.PrintRatio(); 62 } 63 return CheckBreak(); 64} 65 66static void AddMinuses(AString &s, unsigned num) 67{ 68 for (unsigned i = 0; i < num; i++) 69 s += '-'; 70} 71 72static void SetSpaces(char *s, int num) 73{ 74 for (int i = 0; i < num; i++) 75 s[i] = ' '; 76} 77 78static void SetSpacesAndNul(char *s, int num) 79{ 80 SetSpaces(s, num); 81 s[num] = 0; 82} 83 84static void AddSpaces(UString &s, int num) 85{ 86 for (int i = 0; i < num; i++) 87 s += ' '; 88} 89 90static const int kSizeField_Len = 13; 91static const int kNameField_Len = 12; 92 93static unsigned GetColumnWidth(unsigned digestSize) 94{ 95 unsigned width = digestSize * 2; 96 const unsigned kMinColumnWidth = 8; 97 return width < kMinColumnWidth ? kMinColumnWidth: width; 98} 99 100void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers) 101{ 102 AString s; 103 for (unsigned i = 0; i < hashers.Size(); i++) 104 { 105 const CHasherState &h = hashers[i]; 106 AddMinuses(s, GetColumnWidth(h.DigestSize)); 107 s += ' '; 108 } 109 AddMinuses(s, kSizeField_Len); 110 s += " "; 111 AddMinuses(s, kNameField_Len); 112 m_PercentPrinter.PrintString(s); 113 m_PercentPrinter.PrintNewLine(); 114} 115 116HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb) 117{ 118 UString s; 119 FOR_VECTOR (i, hb.Hashers) 120 { 121 const CHasherState &h = hb.Hashers[i]; 122 s += h.Name; 123 AddSpaces(s, (int)GetColumnWidth(h.DigestSize) - h.Name.Len() + 1); 124 } 125 UString s2 = L"Size"; 126 AddSpaces(s, kSizeField_Len - s2.Len()); 127 s += s2; 128 s += L" "; 129 s += L"Name"; 130 m_PercentPrinter.PrintString(s); 131 m_PercentPrinter.PrintNewLine(); 132 PrintSeparatorLine(hb.Hashers); 133 return CheckBreak(); 134} 135 136HRESULT CHashCallbackConsole::OpenFileError(const wchar_t *name, DWORD systemError) 137{ 138 FailedCodes.Add(systemError); 139 FailedFiles.Add(name); 140 // if (systemError == ERROR_SHARING_VIOLATION) 141 { 142 m_PercentPrinter.PrintString(name); 143 m_PercentPrinter.PrintString(": WARNING: "); 144 m_PercentPrinter.PrintString(NWindows::NError::MyFormatMessage(systemError)); 145 return S_FALSE; 146 } 147 // return systemError; 148} 149 150HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool /* isFolder */) 151{ 152 m_FileName = name; 153 return CheckBreak(); 154} 155 156void CHashCallbackConsole::PrintResultLine(UInt64 fileSize, 157 const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash) 158{ 159 FOR_VECTOR (i, hashers) 160 { 161 const CHasherState &h = hashers[i]; 162 163 char s[k_HashCalc_DigestSize_Max * 2 + 64]; 164 s[0] = 0; 165 if (showHash) 166 AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize); 167 SetSpacesAndNul(s + strlen(s), (int)GetColumnWidth(h.DigestSize) - (int)strlen(s) + 1); 168 m_PercentPrinter.PrintString(s); 169 } 170 char s[64]; 171 s[0] = 0; 172 char *p = s; 173 if (showHash && fileSize != 0) 174 { 175 p = s + 32; 176 ConvertUInt64ToString(fileSize, p); 177 int numSpaces = kSizeField_Len - (int)strlen(p); 178 if (numSpaces > 0) 179 { 180 p -= numSpaces; 181 SetSpaces(p, numSpaces); 182 } 183 } 184 else 185 SetSpacesAndNul(s, kSizeField_Len - (int)strlen(s)); 186 unsigned len = (unsigned)strlen(p); 187 p[len] = ' '; 188 p[len + 1] = ' '; 189 p[len + 2] = 0; 190 m_PercentPrinter.PrintString(p); 191} 192 193HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) 194{ 195 PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash); 196 if (m_FileName.IsEmpty()) 197 m_PercentPrinter.PrintString(kEmptyFileAlias); 198 else 199 m_PercentPrinter.PrintString(m_FileName); 200 m_PercentPrinter.PrintNewLine(); 201 return S_OK; 202} 203 204static const char *k_DigestTitles[] = 205{ 206 " :" 207 , " for data: " 208 , " for data and names: " 209 , " for streams and names: " 210}; 211 212static void PrintSum(CStdOutStream &p, const CHasherState &h, unsigned digestIndex) 213{ 214 char s[k_HashCalc_DigestSize_Max * 2 + 64]; 215 UString name = h.Name; 216 AddSpaces(name, 6 - (int)name.Len()); 217 p << name; 218 p << k_DigestTitles[digestIndex]; 219 s[0] = 0; 220 AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize); 221 p << s; 222 p << "\n"; 223} 224 225 226void PrintHashStat(CStdOutStream &p, const CHashBundle &hb) 227{ 228 FOR_VECTOR (i, hb.Hashers) 229 { 230 const CHasherState &h = hb.Hashers[i]; 231 p << "\n"; 232 PrintSum(p, h, k_HashCalc_Index_DataSum); 233 if (hb.NumFiles != 1 || hb.NumDirs != 0) 234 PrintSum(p, h, k_HashCalc_Index_NamesSum); 235 if (hb.NumAltStreams != 0) 236 PrintSum(p, h, k_HashCalc_Index_StreamsSum); 237 } 238} 239 240void CHashCallbackConsole::PrintProperty(const char *name, UInt64 value) 241{ 242 char s[32]; 243 s[0] = ':'; 244 s[1] = ' '; 245 ConvertUInt64ToString(value, s + 2); 246 m_PercentPrinter.PrintString(name); 247 m_PercentPrinter.PrintString(s); 248 m_PercentPrinter.PrintNewLine(); 249} 250 251HRESULT CHashCallbackConsole::AfterLastFile(const CHashBundle &hb) 252{ 253 PrintSeparatorLine(hb.Hashers); 254 255 PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true); 256 m_PercentPrinter.PrintNewLine(); 257 m_PercentPrinter.PrintNewLine(); 258 259 if (hb.NumFiles != 1 || hb.NumDirs != 0) 260 { 261 if (hb.NumDirs != 0) 262 PrintProperty("Folders", hb.NumDirs); 263 PrintProperty("Files", hb.NumFiles); 264 } 265 PrintProperty("Size", hb.FilesSize); 266 if (hb.NumAltStreams != 0) 267 { 268 PrintProperty("AltStreams", hb.NumAltStreams); 269 PrintProperty("AltStreams size", hb.AltStreamsSize); 270 } 271 PrintHashStat(*m_PercentPrinter.OutStream, hb); 272 m_PercentPrinter.PrintNewLine(); 273 return S_OK; 274} 275