xref: /third_party/lzma/CPP/7zip/UI/Console/HashCon.cpp (revision 370b324c)
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
12static const char * const kEmptyFileAlias = "[Content]";
13
14static const char * const kScanningMessage = "Scanning";
15
16static HRESULT CheckBreak2()
17{
18  return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
19}
20
21HRESULT CHashCallbackConsole::CheckBreak()
22{
23  return CheckBreak2();
24}
25
26HRESULT 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
38HRESULT 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
52HRESULT CHashCallbackConsole::ScanError(const FString &path, DWORD systemError)
53{
54  return ScanError_Base(path, systemError);
55}
56
57void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
58
59HRESULT 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
74HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
75{
76  return CheckBreak2();
77}
78
79HRESULT CHashCallbackConsole::SetTotal(UInt64 size)
80{
81  if (NeedPercents())
82  {
83    _percent.Total = size;
84    _percent.Print();
85  }
86  return CheckBreak2();
87}
88
89HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue)
90{
91  if (completeValue && NeedPercents())
92  {
93    _percent.Completed = *completeValue;
94    _percent.Print();
95  }
96  return CheckBreak2();
97}
98
99static void AddMinuses(AString &s, unsigned num)
100{
101  for (unsigned i = 0; i < num; i++)
102    s.Add_Minus();
103}
104
105static void AddSpaces_if_Positive(AString &s, int num)
106{
107  for (int i = 0; i < num; i++)
108    s.Add_Space();
109}
110
111static void SetSpacesAndNul(char *s, unsigned num)
112{
113  for (unsigned i = 0; i < num; i++)
114    s[i] = ' ';
115  s[num] = 0;
116}
117
118static 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
127static const unsigned kSizeField_Len = 13;
128static const unsigned kNameField_Len = 12;
129
130static const unsigned kHashColumnWidth_Min = 4 * 2;
131
132static unsigned GetColumnWidth(unsigned digestSize)
133{
134  unsigned width = digestSize * 2;
135  return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width;
136}
137
138
139AString 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
149void 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
181HRESULT 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
224HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
225{
226  return OpenFileError_Base(path, systemError);
227}
228
229HRESULT 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
249static const unsigned k_DigestStringSize = k_HashCalc_DigestSize_Max * 2 + k_HashCalc_ExtraSize * 2 + 16;
250
251
252
253void 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
307HRESULT 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
345static const char * const k_DigestTitles[] =
346{
347    " : "
348  , " for data:              "
349  , " for data and names:    "
350  , " for streams and names: "
351};
352
353static 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
371void 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
385void 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
394HRESULT 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