368 lines
7.5 KiB
C++
368 lines
7.5 KiB
C++
// HashCon.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../../Common/IntToString.h"
|
|
|
|
#include "ConsoleClose.h"
|
|
#include "HashCon.h"
|
|
|
|
static const wchar_t *kEmptyFileAlias = L"[Content]";
|
|
|
|
static const char *kScanningMessage = "Scanning";
|
|
|
|
static HRESULT CheckBreak2()
|
|
{
|
|
return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::CheckBreak()
|
|
{
|
|
return CheckBreak2();
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::StartScanning()
|
|
{
|
|
if (PrintHeaders && _so)
|
|
*_so << kScanningMessage << endl;
|
|
if (NeedPercents())
|
|
{
|
|
_percent.ClearCurState();
|
|
_percent.Command = "Scan";
|
|
}
|
|
return CheckBreak2();
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */)
|
|
{
|
|
if (NeedPercents())
|
|
{
|
|
_percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams;
|
|
_percent.Completed = st.GetTotalBytes();
|
|
_percent.FileName = fs2us(path);
|
|
_percent.Print();
|
|
}
|
|
return CheckBreak2();
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::ScanError(const FString &path, DWORD systemError)
|
|
{
|
|
return ScanError_Base(path, systemError);
|
|
}
|
|
|
|
void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
|
|
|
|
HRESULT CHashCallbackConsole::FinishScanning(const CDirItemsStat &st)
|
|
{
|
|
if (NeedPercents())
|
|
{
|
|
_percent.ClosePrint(true);
|
|
_percent.ClearCurState();
|
|
}
|
|
if (PrintHeaders && _so)
|
|
{
|
|
Print_DirItemsStat(_s, st);
|
|
*_so << _s << endl << endl;
|
|
}
|
|
return CheckBreak2();
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
|
|
{
|
|
return CheckBreak2();
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::SetTotal(UInt64 size)
|
|
{
|
|
if (NeedPercents())
|
|
{
|
|
_percent.Total = size;
|
|
_percent.Print();
|
|
}
|
|
return CheckBreak2();
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue)
|
|
{
|
|
if (completeValue && NeedPercents())
|
|
{
|
|
_percent.Completed = *completeValue;
|
|
_percent.Print();
|
|
}
|
|
return CheckBreak2();
|
|
}
|
|
|
|
static void AddMinuses(AString &s, unsigned num)
|
|
{
|
|
for (unsigned i = 0; i < num; i++)
|
|
s += '-';
|
|
}
|
|
|
|
static void AddSpaces_if_Positive(AString &s, int num)
|
|
{
|
|
for (int i = 0; i < num; i++)
|
|
s.Add_Space();
|
|
}
|
|
|
|
static void SetSpacesAndNul(char *s, unsigned num)
|
|
{
|
|
for (unsigned i = 0; i < num; i++)
|
|
s[i] = ' ';
|
|
s[num] = 0;
|
|
}
|
|
|
|
static const unsigned kSizeField_Len = 13;
|
|
static const unsigned kNameField_Len = 12;
|
|
|
|
static const unsigned kHashColumnWidth_Min = 4 * 2;
|
|
|
|
static unsigned GetColumnWidth(unsigned digestSize)
|
|
{
|
|
unsigned width = digestSize * 2;
|
|
return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width;
|
|
}
|
|
|
|
void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers)
|
|
{
|
|
_s.Empty();
|
|
|
|
for (unsigned i = 0; i < hashers.Size(); i++)
|
|
{
|
|
if (i != 0)
|
|
_s.Add_Space();
|
|
const CHasherState &h = hashers[i];
|
|
AddMinuses(_s, GetColumnWidth(h.DigestSize));
|
|
}
|
|
|
|
if (PrintSize)
|
|
{
|
|
_s.Add_Space();
|
|
AddMinuses(_s, kSizeField_Len);
|
|
}
|
|
|
|
if (PrintName)
|
|
{
|
|
AddSpacesBeforeName();
|
|
AddMinuses(_s, kNameField_Len);
|
|
}
|
|
|
|
*_so << _s << endl;
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb)
|
|
{
|
|
if (PrintHeaders && _so)
|
|
{
|
|
_s.Empty();
|
|
ClosePercents_for_so();
|
|
|
|
FOR_VECTOR (i, hb.Hashers)
|
|
{
|
|
if (i != 0)
|
|
_s.Add_Space();
|
|
const CHasherState &h = hb.Hashers[i];
|
|
_s += h.Name;
|
|
AddSpaces_if_Positive(_s, (int)GetColumnWidth(h.DigestSize) - (int)h.Name.Len());
|
|
}
|
|
|
|
if (PrintSize)
|
|
{
|
|
_s.Add_Space();
|
|
const AString s2 = "Size";
|
|
AddSpaces_if_Positive(_s, (int)kSizeField_Len - (int)s2.Len());
|
|
_s += s2;
|
|
}
|
|
|
|
if (PrintName)
|
|
{
|
|
AddSpacesBeforeName();
|
|
_s += "Name";
|
|
}
|
|
|
|
*_so << _s << endl;
|
|
PrintSeparatorLine(hb.Hashers);
|
|
}
|
|
|
|
return CheckBreak2();
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
|
|
{
|
|
return OpenFileError_Base(path, systemError);
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool /* isFolder */)
|
|
{
|
|
_fileName = name;
|
|
|
|
if (NeedPercents())
|
|
{
|
|
if (PrintNameInPercents)
|
|
{
|
|
_percent.FileName.Empty();
|
|
if (name)
|
|
_percent.FileName = name;
|
|
}
|
|
_percent.Print();
|
|
}
|
|
return CheckBreak2();
|
|
}
|
|
|
|
void CHashCallbackConsole::PrintResultLine(UInt64 fileSize,
|
|
const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash)
|
|
{
|
|
ClosePercents_for_so();
|
|
|
|
_s.Empty();
|
|
|
|
FOR_VECTOR (i, hashers)
|
|
{
|
|
const CHasherState &h = hashers[i];
|
|
char s[k_HashCalc_DigestSize_Max * 2 + 64];
|
|
s[0] = 0;
|
|
if (showHash)
|
|
AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize);
|
|
SetSpacesAndNul(s + strlen(s), (int)GetColumnWidth(h.DigestSize) - (int)strlen(s));
|
|
if (i != 0)
|
|
_s.Add_Space();
|
|
_s += s;
|
|
}
|
|
|
|
if (PrintSize)
|
|
{
|
|
_s.Add_Space();
|
|
|
|
char s[kSizeField_Len + 32];
|
|
char *p = s;
|
|
|
|
if (showHash)
|
|
{
|
|
p = s + kSizeField_Len;
|
|
ConvertUInt64ToString(fileSize, p);
|
|
int numSpaces = kSizeField_Len - (int)strlen(p);
|
|
if (numSpaces > 0)
|
|
{
|
|
p -= (unsigned)numSpaces;
|
|
for (unsigned i = 0; i < (unsigned)numSpaces; i++)
|
|
p[i] = ' ';
|
|
}
|
|
}
|
|
else
|
|
SetSpacesAndNul(s, kSizeField_Len);
|
|
|
|
_s += p;
|
|
}
|
|
|
|
if (PrintName)
|
|
AddSpacesBeforeName();
|
|
|
|
*_so << _s;
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash)
|
|
{
|
|
if (_so)
|
|
{
|
|
PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash);
|
|
if (PrintName)
|
|
{
|
|
if (_fileName.IsEmpty())
|
|
*_so << kEmptyFileAlias;
|
|
else
|
|
*_so << _fileName;
|
|
}
|
|
*_so << endl;
|
|
}
|
|
|
|
if (NeedPercents())
|
|
{
|
|
_percent.Files++;
|
|
_percent.Print();
|
|
}
|
|
|
|
return CheckBreak2();
|
|
}
|
|
|
|
static const char *k_DigestTitles[] =
|
|
{
|
|
" : "
|
|
, " for data: "
|
|
, " for data and names: "
|
|
, " for streams and names: "
|
|
};
|
|
|
|
static void PrintSum(CStdOutStream &so, const CHasherState &h, unsigned digestIndex)
|
|
{
|
|
so << h.Name;
|
|
|
|
{
|
|
AString temp;
|
|
AddSpaces_if_Positive(temp, 6 - (int)h.Name.Len());
|
|
so << temp;
|
|
}
|
|
|
|
so << k_DigestTitles[digestIndex];
|
|
|
|
char s[k_HashCalc_DigestSize_Max * 2 + 64];
|
|
s[0] = 0;
|
|
AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize);
|
|
so << s << endl;
|
|
}
|
|
|
|
void PrintHashStat(CStdOutStream &so, const CHashBundle &hb)
|
|
{
|
|
FOR_VECTOR (i, hb.Hashers)
|
|
{
|
|
const CHasherState &h = hb.Hashers[i];
|
|
PrintSum(so, h, k_HashCalc_Index_DataSum);
|
|
if (hb.NumFiles != 1 || hb.NumDirs != 0)
|
|
PrintSum(so, h, k_HashCalc_Index_NamesSum);
|
|
if (hb.NumAltStreams != 0)
|
|
PrintSum(so, h, k_HashCalc_Index_StreamsSum);
|
|
so << endl;
|
|
}
|
|
}
|
|
|
|
void CHashCallbackConsole::PrintProperty(const char *name, UInt64 value)
|
|
{
|
|
char s[32];
|
|
s[0] = ':';
|
|
s[1] = ' ';
|
|
ConvertUInt64ToString(value, s + 2);
|
|
*_so << name << s << endl;
|
|
}
|
|
|
|
HRESULT CHashCallbackConsole::AfterLastFile(const CHashBundle &hb)
|
|
{
|
|
ClosePercents2();
|
|
|
|
if (PrintHeaders && _so)
|
|
{
|
|
PrintSeparatorLine(hb.Hashers);
|
|
|
|
PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true);
|
|
|
|
*_so << endl << endl;
|
|
|
|
if (hb.NumFiles != 1 || hb.NumDirs != 0)
|
|
{
|
|
if (hb.NumDirs != 0)
|
|
PrintProperty("Folders", hb.NumDirs);
|
|
PrintProperty("Files", hb.NumFiles);
|
|
}
|
|
|
|
PrintProperty("Size", hb.FilesSize);
|
|
|
|
if (hb.NumAltStreams != 0)
|
|
{
|
|
PrintProperty("Alternate streams", hb.NumAltStreams);
|
|
PrintProperty("Alternate streams size", hb.AltStreamsSize);
|
|
}
|
|
|
|
*_so << endl;
|
|
PrintHashStat(*_so, hb);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|