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 13 static const wchar_t *kEmptyFileAlias = L"[Content]"; 14 15 static const char *kScanningMessage = "Scanning"; 16 17 HRESULT CHashCallbackConsole::CheckBreak() 18 { 19 return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; 20 } 21 22 HRESULT CHashCallbackConsole::StartScanning() 23 { 24 (*OutStream) << kScanningMessage; 25 return CheckBreak(); 26 } 27 28 HRESULT CHashCallbackConsole::ScanProgress(UInt64 /* numFolders */, UInt64 /* numFiles */, UInt64 /* totalSize */, const wchar_t * /* path */, bool /* isDir */) 29 { 30 return CheckBreak(); 31 } 32 33 HRESULT CHashCallbackConsole::CanNotFindError(const wchar_t *name, DWORD systemError) 34 { 35 return CanNotFindError_Base(name, systemError); 36 } 37 38 HRESULT CHashCallbackConsole::FinishScanning() 39 { 40 (*OutStream) << endl << endl; 41 return CheckBreak(); 42 } 43 44 HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */) 45 { 46 return CheckBreak(); 47 } 48 49 HRESULT CHashCallbackConsole::SetTotal(UInt64 size) 50 { 51 if (EnablePercents) 52 m_PercentPrinter.SetTotal(size); 53 return CheckBreak(); 54 } 55 56 HRESULT 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 66 static void AddMinuses(AString &s, unsigned num) 67 { 68 for (unsigned i = 0; i < num; i++) 69 s += '-'; 70 } 71 72 static void SetSpaces(char *s, int num) 73 { 74 for (int i = 0; i < num; i++) 75 s[i] = ' '; 76 } 77 78 static void SetSpacesAndNul(char *s, int num) 79 { 80 SetSpaces(s, num); 81 s[num] = 0; 82 } 83 84 static void AddSpaces(UString &s, int num) 85 { 86 for (int i = 0; i < num; i++) 87 s += ' '; 88 } 89 90 static const int kSizeField_Len = 13; 91 static const int kNameField_Len = 12; 92 93 static unsigned GetColumnWidth(unsigned digestSize) 94 { 95 unsigned width = digestSize * 2; 96 const unsigned kMinColumnWidth = 8; 97 return width < kMinColumnWidth ? kMinColumnWidth: width; 98 } 99 100 void 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 116 HRESULT 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 136 HRESULT 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 150 HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool /* isFolder */) 151 { 152 m_FileName = name; 153 return CheckBreak(); 154 } 155 156 void 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 193 HRESULT 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 204 static const char *k_DigestTitles[] = 205 { 206 " :" 207 , " for data: " 208 , " for data and names: " 209 , " for streams and names: " 210 }; 211 212 static 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 226 void 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 240 void 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 251 HRESULT 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