• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CheckBreak2()14 static HRESULT CheckBreak2()
15 {
16   return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
17 }
18 
CheckBreak()19 HRESULT CHashCallbackConsole::CheckBreak()
20 {
21   return CheckBreak2();
22 }
23 
StartScanning()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 
ScanProgress(const CDirItemsStat & st,const FString & path,bool)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 
ScanError(const FString & path,DWORD systemError)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 
FinishScanning(const CDirItemsStat & st)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 
SetNumFiles(UInt64)70 HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
71 {
72   return CheckBreak2();
73 }
74 
SetTotal(UInt64 size)75 HRESULT CHashCallbackConsole::SetTotal(UInt64 size)
76 {
77   if (NeedPercents())
78   {
79     _percent.Total = size;
80     _percent.Print();
81   }
82   return CheckBreak2();
83 }
84 
SetCompleted(const UInt64 * completeValue)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 
AddMinuses(AString & s,unsigned num)95 static void AddMinuses(AString &s, unsigned num)
96 {
97   for (unsigned i = 0; i < num; i++)
98     s += '-';
99 }
100 
AddSpaces_if_Positive(AString & s,int num)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 
SetSpacesAndNul(char * s,unsigned num)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 
GetColumnWidth(unsigned digestSize)119 static unsigned GetColumnWidth(unsigned digestSize)
120 {
121   unsigned width = digestSize * 2;
122   return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width;
123 }
124 
PrintSeparatorLine(const CObjectVector<CHasherState> & hashers)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 
BeforeFirstFile(const CHashBundle & hb)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 
OpenFileError(const FString & path,DWORD systemError)189 HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
190 {
191   return OpenFileError_Base(path, systemError);
192 }
193 
GetStream(const wchar_t * name,bool)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 
PrintResultLine(UInt64 fileSize,const CObjectVector<CHasherState> & hashers,unsigned digestIndex,bool showHash)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 
SetOperationResult(UInt64 fileSize,const CHashBundle & hb,bool showHash)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 
PrintSum(CStdOutStream & so,const CHasherState & h,unsigned digestIndex)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 
PrintHashStat(CStdOutStream & so,const CHashBundle & hb)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 
PrintProperty(const char * name,UInt64 value)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 
AfterLastFile(const CHashBundle & hb)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