1 // HashCon.cpp 2 3 #include "StdAfx.h" 4 5 #include "../../../Common/IntToString.h" 6 7 #include "ConsoleClose.h" 8 #include "HashCon.h" 9 10 static const wchar_t *kEmptyFileAlias = L"[Content]"; 11 12 static const char *kScanningMessage = "Scanning"; 13 14 static HRESULT CheckBreak2() 15 { 16 return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; 17 } 18 19 HRESULT CHashCallbackConsole::CheckBreak() 20 { 21 return CheckBreak2(); 22 } 23 24 HRESULT CHashCallbackConsole::StartScanning() 25 { 26 if (PrintHeaders && _so) 27 *_so << kScanningMessage << endl; 28 if (NeedPercents()) 29 { 30 _percent.ClearCurState(); 31 _percent.Command = "Scan"; 32 } 33 return CheckBreak2(); 34 } 35 36 HRESULT CHashCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */) 37 { 38 if (NeedPercents()) 39 { 40 _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams; 41 _percent.Completed = st.GetTotalBytes(); 42 _percent.FileName = fs2us(path); 43 _percent.Print(); 44 } 45 return CheckBreak2(); 46 } 47 48 HRESULT CHashCallbackConsole::ScanError(const FString &path, DWORD systemError) 49 { 50 return ScanError_Base(path, systemError); 51 } 52 53 void Print_DirItemsStat(AString &s, const CDirItemsStat &st); 54 55 HRESULT CHashCallbackConsole::FinishScanning(const CDirItemsStat &st) 56 { 57 if (NeedPercents()) 58 { 59 _percent.ClosePrint(true); 60 _percent.ClearCurState(); 61 } 62 if (PrintHeaders && _so) 63 { 64 Print_DirItemsStat(_s, st); 65 *_so << _s << endl << endl; 66 } 67 return CheckBreak2(); 68 } 69 70 HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */) 71 { 72 return CheckBreak2(); 73 } 74 75 HRESULT CHashCallbackConsole::SetTotal(UInt64 size) 76 { 77 if (NeedPercents()) 78 { 79 _percent.Total = size; 80 _percent.Print(); 81 } 82 return CheckBreak2(); 83 } 84 85 HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue) 86 { 87 if (completeValue && NeedPercents()) 88 { 89 _percent.Completed = *completeValue; 90 _percent.Print(); 91 } 92 return CheckBreak2(); 93 } 94 95 static void AddMinuses(AString &s, unsigned num) 96 { 97 for (unsigned i = 0; i < num; i++) 98 s += '-'; 99 } 100 101 static void AddSpaces_if_Positive(AString &s, int num) 102 { 103 for (int i = 0; i < num; i++) 104 s.Add_Space(); 105 } 106 107 static void SetSpacesAndNul(char *s, unsigned num) 108 { 109 for (unsigned i = 0; i < num; i++) 110 s[i] = ' '; 111 s[num] = 0; 112 } 113 114 static const unsigned kSizeField_Len = 13; 115 static const unsigned kNameField_Len = 12; 116 117 static const unsigned kHashColumnWidth_Min = 4 * 2; 118 119 static unsigned GetColumnWidth(unsigned digestSize) 120 { 121 unsigned width = digestSize * 2; 122 return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width; 123 } 124 125 void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers) 126 { 127 _s.Empty(); 128 129 for (unsigned i = 0; i < hashers.Size(); i++) 130 { 131 if (i != 0) 132 _s.Add_Space(); 133 const CHasherState &h = hashers[i]; 134 AddMinuses(_s, GetColumnWidth(h.DigestSize)); 135 } 136 137 if (PrintSize) 138 { 139 _s.Add_Space(); 140 AddMinuses(_s, kSizeField_Len); 141 } 142 143 if (PrintName) 144 { 145 AddSpacesBeforeName(); 146 AddMinuses(_s, kNameField_Len); 147 } 148 149 *_so << _s << endl; 150 } 151 152 HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb) 153 { 154 if (PrintHeaders && _so) 155 { 156 _s.Empty(); 157 ClosePercents_for_so(); 158 159 FOR_VECTOR (i, hb.Hashers) 160 { 161 if (i != 0) 162 _s.Add_Space(); 163 const CHasherState &h = hb.Hashers[i]; 164 _s += h.Name; 165 AddSpaces_if_Positive(_s, (int)GetColumnWidth(h.DigestSize) - (int)h.Name.Len()); 166 } 167 168 if (PrintSize) 169 { 170 _s.Add_Space(); 171 const AString s2 = "Size"; 172 AddSpaces_if_Positive(_s, (int)kSizeField_Len - (int)s2.Len()); 173 _s += s2; 174 } 175 176 if (PrintName) 177 { 178 AddSpacesBeforeName(); 179 _s += "Name"; 180 } 181 182 *_so << _s << endl; 183 PrintSeparatorLine(hb.Hashers); 184 } 185 186 return CheckBreak2(); 187 } 188 189 HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemError) 190 { 191 return OpenFileError_Base(path, systemError); 192 } 193 194 HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool /* isFolder */) 195 { 196 _fileName = name; 197 198 if (NeedPercents()) 199 { 200 if (PrintNameInPercents) 201 { 202 _percent.FileName.Empty(); 203 if (name) 204 _percent.FileName = name; 205 } 206 _percent.Print(); 207 } 208 return CheckBreak2(); 209 } 210 211 void CHashCallbackConsole::PrintResultLine(UInt64 fileSize, 212 const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash) 213 { 214 ClosePercents_for_so(); 215 216 _s.Empty(); 217 218 FOR_VECTOR (i, hashers) 219 { 220 const CHasherState &h = hashers[i]; 221 char s[k_HashCalc_DigestSize_Max * 2 + 64]; 222 s[0] = 0; 223 if (showHash) 224 AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize); 225 SetSpacesAndNul(s + strlen(s), (int)GetColumnWidth(h.DigestSize) - (int)strlen(s)); 226 if (i != 0) 227 _s.Add_Space(); 228 _s += s; 229 } 230 231 if (PrintSize) 232 { 233 _s.Add_Space(); 234 235 char s[kSizeField_Len + 32]; 236 char *p = s; 237 238 if (showHash) 239 { 240 p = s + kSizeField_Len; 241 ConvertUInt64ToString(fileSize, p); 242 int numSpaces = kSizeField_Len - (int)strlen(p); 243 if (numSpaces > 0) 244 { 245 p -= (unsigned)numSpaces; 246 for (unsigned i = 0; i < (unsigned)numSpaces; i++) 247 p[i] = ' '; 248 } 249 } 250 else 251 SetSpacesAndNul(s, kSizeField_Len); 252 253 _s += p; 254 } 255 256 if (PrintName) 257 AddSpacesBeforeName(); 258 259 *_so << _s; 260 } 261 262 HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) 263 { 264 if (_so) 265 { 266 PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash); 267 if (PrintName) 268 { 269 if (_fileName.IsEmpty()) 270 *_so << kEmptyFileAlias; 271 else 272 *_so << _fileName; 273 } 274 *_so << endl; 275 } 276 277 if (NeedPercents()) 278 { 279 _percent.Files++; 280 _percent.Print(); 281 } 282 283 return CheckBreak2(); 284 } 285 286 static const char * const k_DigestTitles[] = 287 { 288 " : " 289 , " for data: " 290 , " for data and names: " 291 , " for streams and names: " 292 }; 293 294 static void PrintSum(CStdOutStream &so, const CHasherState &h, unsigned digestIndex) 295 { 296 so << h.Name; 297 298 { 299 AString temp; 300 AddSpaces_if_Positive(temp, 6 - (int)h.Name.Len()); 301 so << temp; 302 } 303 304 so << k_DigestTitles[digestIndex]; 305 306 char s[k_HashCalc_DigestSize_Max * 2 + 64]; 307 s[0] = 0; 308 AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize); 309 so << s << endl; 310 } 311 312 void PrintHashStat(CStdOutStream &so, const CHashBundle &hb) 313 { 314 FOR_VECTOR (i, hb.Hashers) 315 { 316 const CHasherState &h = hb.Hashers[i]; 317 PrintSum(so, h, k_HashCalc_Index_DataSum); 318 if (hb.NumFiles != 1 || hb.NumDirs != 0) 319 PrintSum(so, h, k_HashCalc_Index_NamesSum); 320 if (hb.NumAltStreams != 0) 321 PrintSum(so, h, k_HashCalc_Index_StreamsSum); 322 so << endl; 323 } 324 } 325 326 void CHashCallbackConsole::PrintProperty(const char *name, UInt64 value) 327 { 328 char s[32]; 329 s[0] = ':'; 330 s[1] = ' '; 331 ConvertUInt64ToString(value, s + 2); 332 *_so << name << s << endl; 333 } 334 335 HRESULT CHashCallbackConsole::AfterLastFile(const CHashBundle &hb) 336 { 337 ClosePercents2(); 338 339 if (PrintHeaders && _so) 340 { 341 PrintSeparatorLine(hb.Hashers); 342 343 PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true); 344 345 *_so << endl << endl; 346 347 if (hb.NumFiles != 1 || hb.NumDirs != 0) 348 { 349 if (hb.NumDirs != 0) 350 PrintProperty("Folders", hb.NumDirs); 351 PrintProperty("Files", hb.NumFiles); 352 } 353 354 PrintProperty("Size", hb.FilesSize); 355 356 if (hb.NumAltStreams != 0) 357 { 358 PrintProperty("Alternate streams", hb.NumAltStreams); 359 PrintProperty("Alternate streams size", hb.AltStreamsSize); 360 } 361 362 *_so << endl; 363 PrintHashStat(*_so, hb); 364 } 365 366 return S_OK; 367 } 368