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 
CheckBreak()17 HRESULT CHashCallbackConsole::CheckBreak()
18 {
19   return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
20 }
21 
StartScanning()22 HRESULT CHashCallbackConsole::StartScanning()
23 {
24   (*OutStream) << kScanningMessage;
25   return CheckBreak();
26 }
27 
ScanProgress(UInt64,UInt64,UInt64,const wchar_t *,bool)28 HRESULT CHashCallbackConsole::ScanProgress(UInt64 /* numFolders */, UInt64 /* numFiles */, UInt64 /* totalSize */, const wchar_t * /* path */, bool /* isDir */)
29 {
30   return CheckBreak();
31 }
32 
CanNotFindError(const wchar_t * name,DWORD systemError)33 HRESULT CHashCallbackConsole::CanNotFindError(const wchar_t *name, DWORD systemError)
34 {
35   return CanNotFindError_Base(name, systemError);
36 }
37 
FinishScanning()38 HRESULT CHashCallbackConsole::FinishScanning()
39 {
40   (*OutStream) << endl << endl;
41   return CheckBreak();
42 }
43 
SetNumFiles(UInt64)44 HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
45 {
46   return CheckBreak();
47 }
48 
SetTotal(UInt64 size)49 HRESULT CHashCallbackConsole::SetTotal(UInt64 size)
50 {
51   if (EnablePercents)
52     m_PercentPrinter.SetTotal(size);
53   return CheckBreak();
54 }
55 
SetCompleted(const UInt64 * completeValue)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 
AddMinuses(AString & s,unsigned num)66 static void AddMinuses(AString &s, unsigned num)
67 {
68   for (unsigned i = 0; i < num; i++)
69     s += '-';
70 }
71 
SetSpaces(char * s,int num)72 static void SetSpaces(char *s, int num)
73 {
74   for (int i = 0; i < num; i++)
75     s[i] = ' ';
76 }
77 
SetSpacesAndNul(char * s,int num)78 static void SetSpacesAndNul(char *s, int num)
79 {
80   SetSpaces(s, num);
81   s[num] = 0;
82 }
83 
AddSpaces(UString & s,int num)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 
GetColumnWidth(unsigned digestSize)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 
PrintSeparatorLine(const CObjectVector<CHasherState> & hashers)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 
BeforeFirstFile(const CHashBundle & hb)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 
OpenFileError(const wchar_t * name,DWORD systemError)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 
GetStream(const wchar_t * name,bool)150 HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool /* isFolder */)
151 {
152   m_FileName = name;
153   return CheckBreak();
154 }
155 
PrintResultLine(UInt64 fileSize,const CObjectVector<CHasherState> & hashers,unsigned digestIndex,bool showHash)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 
SetOperationResult(UInt64 fileSize,const CHashBundle & hb,bool showHash)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 
PrintSum(CStdOutStream & p,const CHasherState & h,unsigned digestIndex)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 
PrintHashStat(CStdOutStream & p,const CHashBundle & hb)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 
PrintProperty(const char * name,UInt64 value)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 
AfterLastFile(const CHashBundle & hb)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