• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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