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