Home | History | Annotate | Download | only in Console
      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 
     14 static HRESULT CheckBreak2()
     15 {
     16   return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
     17 }
     18 
     19 HRESULT CHashCallbackConsole::CheckBreak()
     20 {
     21   return CheckBreak2();
     22 }
     23 
     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 
     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 
     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 
     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 
     70 HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
     71 {
     72   return CheckBreak2();
     73 }
     74 
     75 HRESULT CHashCallbackConsole::SetTotal(UInt64 size)
     76 {
     77   if (NeedPercents())
     78   {
     79     _percent.Total = size;
     80     _percent.Print();
     81   }
     82   return CheckBreak2();
     83 }
     84 
     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 
     95 static void AddMinuses(AString &s, unsigned num)
     96 {
     97   for (unsigned i = 0; i < num; i++)
     98     s += '-';
     99 }
    100 
    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 
    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 
    119 static unsigned GetColumnWidth(unsigned digestSize)
    120 {
    121   unsigned width = digestSize * 2;
    122   return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width;
    123 }
    124 
    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 
    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 
    189 HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
    190 {
    191   return OpenFileError_Base(path, systemError);
    192 }
    193 
    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 
    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 
    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 
    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 
    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 
    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 
    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