// PanelSplitFile.cpp #include "StdAfx.h" #include "../../../../C/7zCrc.h" #include "../../../../C/Sha256.h" #include "Common/IntToString.h" #include "Windows/FileFind.h" #include "Windows/FileIO.h" #include "Windows/FileName.h" #include "OverwriteDialogRes.h" #include "App.h" #include "FormatUtils.h" #include "LangUtils.h" #include "../Common/PropIDUtils.h" #include "resource.h" using namespace NWindows; using namespace NFile; static const UInt32 kBufSize = (1 << 15); struct CDirEnumerator { bool FlatMode; UString BasePrefix; UStringVector FileNames; CObjectVector Enumerators; UStringVector Prefixes; int Index; HRESULT GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &fullPath); void Init(); CDirEnumerator(): FlatMode(false) {}; }; void CDirEnumerator::Init() { Enumerators.Clear(); Prefixes.Clear(); Index = 0; } static HRESULT GetNormalizedError() { HRESULT errorCode = GetLastError(); return (errorCode == 0) ? E_FAIL : errorCode; } HRESULT CDirEnumerator::GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &resPath) { filled = false; for (;;) { if (Enumerators.IsEmpty()) { if (Index >= FileNames.Size()) return S_OK; const UString &path = FileNames[Index]; int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR); resPath.Empty(); if (pos >= 0) resPath = path.Left(pos + 1); #ifdef _WIN32 // it's for "c:" paths/ if (BasePrefix.IsEmpty() && path.Length() == 2 && path[1] == ':') { fileInfo.Name = path; fileInfo.Attrib = FILE_ATTRIBUTE_DIRECTORY; fileInfo.Size = 0; } else #endif if (!fileInfo.Find(BasePrefix + path)) { WRes errorCode = GetNormalizedError(); resPath = path; return errorCode; } Index++; break; } bool found; if (!Enumerators.Back().Next(fileInfo, found)) { HRESULT errorCode = GetNormalizedError(); resPath = Prefixes.Back(); return errorCode; } if (found) { resPath = Prefixes.Back(); break; } Enumerators.DeleteBack(); Prefixes.DeleteBack(); } resPath += fileInfo.Name; if (!FlatMode && fileInfo.IsDir()) { UString prefix = resPath + WCHAR_PATH_SEPARATOR; Enumerators.Add(NFind::CEnumeratorW(BasePrefix + prefix + (UString)(wchar_t)NName::kAnyStringWildcard)); Prefixes.Add(prefix); } filled = true; return S_OK; } static void ConvertByteToHex(unsigned value, wchar_t *s) { for (int i = 0; i < 2; i++) { unsigned t = value & 0xF; value >>= 4; s[1 - i] = (wchar_t)((t < 10) ? (L'0' + t) : (L'A' + (t - 10))); } } class CThreadCrc: public CProgressThreadVirt { UInt64 NumFilesScan; UInt64 NumFiles; UInt64 NumFolders; UInt64 DataSize; UInt32 DataCrcSum; Byte Sha256Sum[SHA256_DIGEST_SIZE]; UInt32 DataNameCrcSum; UString GetResultMessage() const; HRESULT ProcessVirt(); public: CDirEnumerator Enumerator; }; UString CThreadCrc::GetResultMessage() const { UString s; wchar_t sz[32]; s += LangString(IDS_FILES_COLON, 0x02000320); s += L' '; ConvertUInt64ToString(NumFiles, sz); s += sz; s += L'\n'; s += LangString(IDS_FOLDERS_COLON, 0x02000321); s += L' '; ConvertUInt64ToString(NumFolders, sz); s += sz; s += L'\n'; s += LangString(IDS_SIZE_COLON, 0x02000322); s += L' '; ConvertUInt64ToString(DataSize, sz); s += MyFormatNew(IDS_FILE_SIZE, 0x02000982, sz); s += L'\n'; s += LangString(IDS_CHECKSUM_CRC_DATA, 0x03020721); s += L' '; ConvertUInt32ToHex(DataCrcSum, sz); s += sz; s += L'\n'; s += LangString(IDS_CHECKSUM_CRC_DATA_NAMES, 0x03020722); s += L' '; ConvertUInt32ToHex(DataNameCrcSum, sz); s += sz; s += L'\n'; if (NumFiles == 1 && NumFilesScan == 1) { s += L"SHA-256: "; for (int i = 0; i < SHA256_DIGEST_SIZE; i++) { wchar_t s2[4]; ConvertByteToHex(Sha256Sum[i], s2); s2[2] = 0; s += s2; } } return s; } HRESULT CThreadCrc::ProcessVirt() { DataSize = NumFolders = NumFiles = NumFilesScan = DataCrcSum = DataNameCrcSum = 0; memset(Sha256Sum, 0, SHA256_DIGEST_SIZE); // ProgressDialog.WaitCreating(); CMyBuffer bufferObject; if (!bufferObject.Allocate(kBufSize)) return E_OUTOFMEMORY; Byte *buffer = (Byte *)(void *)bufferObject; UInt64 totalSize = 0; Enumerator.Init(); UString scanningStr = LangString(IDS_SCANNING, 0x03020800); scanningStr += L' '; CProgressSync &sync = ProgressDialog.Sync; for (;;) { NFind::CFileInfoW fileInfo; bool filled; UString resPath; HRESULT errorCode = Enumerator.GetNextFile(fileInfo, filled, resPath); if (errorCode != 0) { ErrorPath1 = resPath; return errorCode; } if (!filled) break; if (!fileInfo.IsDir()) { totalSize += fileInfo.Size; NumFilesScan++; } sync.SetCurrentFileName(scanningStr + resPath); sync.SetProgress(totalSize, 0); RINOK(sync.SetPosAndCheckPaused(0)); } sync.SetNumFilesTotal(NumFilesScan); sync.SetProgress(totalSize, 0); Enumerator.Init(); for (;;) { NFind::CFileInfoW fileInfo; bool filled; UString resPath; HRESULT errorCode = Enumerator.GetNextFile(fileInfo, filled, resPath); if (errorCode != 0) { ErrorPath1 = resPath; return errorCode; } if (!filled) break; UInt32 crc = CRC_INIT_VAL; CSha256 sha256; Sha256_Init(&sha256); if (fileInfo.IsDir()) NumFolders++; else { NIO::CInFile inFile; if (!inFile.Open(Enumerator.BasePrefix + resPath)) { errorCode = GetNormalizedError(); ErrorPath1 = resPath; return errorCode; } sync.SetCurrentFileName(resPath); sync.SetNumFilesCur(NumFiles); NumFiles++; for (;;) { UInt32 processedSize; if (!inFile.Read(buffer, kBufSize, processedSize)) { errorCode = GetNormalizedError(); ErrorPath1 = resPath; return errorCode; } if (processedSize == 0) break; crc = CrcUpdate(crc, buffer, processedSize); if (NumFilesScan == 1) Sha256_Update(&sha256, buffer, processedSize); DataSize += processedSize; RINOK(sync.SetPosAndCheckPaused(DataSize)); } DataCrcSum += CRC_GET_DIGEST(crc); if (NumFilesScan == 1) Sha256_Final(&sha256, Sha256Sum); } for (int i = 0; i < resPath.Length(); i++) { wchar_t c = resPath[i]; crc = CRC_UPDATE_BYTE(crc, ((Byte)(c & 0xFF))); crc = CRC_UPDATE_BYTE(crc, ((Byte)((c >> 8) & 0xFF))); } DataNameCrcSum += CRC_GET_DIGEST(crc); RINOK(sync.SetPosAndCheckPaused(DataSize)); } sync.SetNumFilesCur(NumFiles); OkMessage = GetResultMessage(); OkMessageTitle = LangString(IDS_CHECKSUM_INFORMATION, 0x03020720); return S_OK; } void CApp::CalculateCrc() { int srcPanelIndex = GetFocusedPanelIndex(); CPanel &srcPanel = Panels[srcPanelIndex]; if (!srcPanel.IsFsOrDrivesFolder()) { srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208); return; } CRecordVector indices; srcPanel.GetOperatedItemIndices(indices); if (indices.IsEmpty()) return; { CThreadCrc t; for (int i = 0; i < indices.Size(); i++) t.Enumerator.FileNames.Add(srcPanel.GetItemRelPath(indices[i])); t.Enumerator.BasePrefix = srcPanel.GetFsPath(); t.Enumerator.FlatMode = GetFlatMode(); t.ProgressDialog.ShowCompressionInfo = false; UString title = LangString(IDS_CHECKSUM_CALCULATING, 0x03020710); t.ProgressDialog.MainWindow = _window; t.ProgressDialog.MainTitle = LangString(IDS_APP_TITLE, 0x03000000); t.ProgressDialog.MainAddTitle = title + UString(L' '); if (t.Create(title, _window) != S_OK) return; } RefreshTitleAlways(); }