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