// PanelSplitFile.cpp #include "StdAfx.h" extern "C" { #include "../../../../C/Alloc.h" #include "../../../../C/7zCrc.h" #include "../../../../C/Sha256.h" } #include "Common/IntToString.h" #include "Common/StringConvert.h" #include "Windows/Error.h" #include "Windows/FileFind.h" #include "Windows/FileIO.h" #include "Windows/FileName.h" #include "Windows/Thread.h" #include "OverwriteDialogRes.h" #include "ProgressDialog2.h" #include "App.h" #include "FormatUtils.h" #include "LangUtils.h" #include "resource.h" using namespace NWindows; using namespace NFile; using namespace NName; static const UInt32 kBufSize = (1 << 15); struct CDirEnumerator { bool FlatMode; UString BasePrefix; UStringVector FileNames; CObjectVector Enumerators; UStringVector Prefixes; int Index; bool GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &fullPath, DWORD &errorCode); void Init(); CDirEnumerator(): FlatMode(false) {}; }; void CDirEnumerator::Init() { Enumerators.Clear(); Prefixes.Clear(); Index = 0; } bool CDirEnumerator::GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &resPath, DWORD &errorCode) { filled = false; for (;;) { if (Enumerators.IsEmpty()) { if (Index >= FileNames.Size()) return true; const UString &path = FileNames[Index]; int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR); resPath.Empty(); if (pos >= 0) resPath = path.Left(pos + 1); if (!NFind::FindFile(BasePrefix + path, fileInfo)) { errorCode = ::GetLastError(); resPath = path; return false; } Index++; break; } bool found; if (!Enumerators.Back().Next(fileInfo, found)) { errorCode = ::GetLastError(); resPath = Prefixes.Back(); return false; } if (found) { resPath = Prefixes.Back(); break; } Enumerators.DeleteBack(); Prefixes.DeleteBack(); } resPath += fileInfo.Name; if (!FlatMode && fileInfo.IsDir()) { UString prefix = resPath + (UString)(wchar_t)kDirDelimiter; Enumerators.Add(NFind::CEnumeratorW(BasePrefix + prefix + (UString)(wchar_t)kAnyStringWildcard)); Prefixes.Add(prefix); } filled = true; return true; } struct CThreadCrc { class CMyBuffer { void *_data; public: CMyBuffer(): _data(0) {} operator void *() { return _data; } bool Allocate(size_t size) { if (_data != 0) return false; _data = ::MidAlloc(size); return _data != 0; } ~CMyBuffer() { ::MidFree(_data); } }; CProgressDialog *ProgressDialog; CDirEnumerator DirEnumerator; UInt64 NumFilesScan; UInt64 NumFiles; UInt64 NumFolders; UInt64 DataSize; UInt32 DataCrcSum; Byte Sha256Sum[SHA256_DIGEST_SIZE]; UInt32 DataNameCrcSum; HRESULT Result; DWORD ErrorCode; UString ErrorPath; UString Error; bool ThereIsError; void Process2() { DataSize = NumFolders = NumFiles = NumFilesScan = DataCrcSum = DataNameCrcSum = 0; memset(Sha256Sum, 0, SHA256_DIGEST_SIZE); ProgressDialog->WaitCreating(); CMyBuffer bufferObject; if (!bufferObject.Allocate(kBufSize)) { Error = L"Can not allocate memory"; ThereIsError = true; return; } Byte *buffer = (Byte *)(void *)bufferObject; UInt64 totalSize = 0; DirEnumerator.Init(); UString scanningStr = LangString(IDS_SCANNING, 0x03020800); scanningStr += L" "; for (;;) { NFile::NFind::CFileInfoW fileInfo; bool filled; UString resPath; if (!DirEnumerator.GetNextFile(fileInfo, filled, resPath, ErrorCode)) { ThereIsError = true; ErrorPath = resPath; return; } if (!filled) break; if (!fileInfo.IsDir()) { totalSize += fileInfo.Size; NumFilesScan++; } ProgressDialog->ProgressSynch.SetCurrentFileName(scanningStr + resPath); ProgressDialog->ProgressSynch.SetProgress(totalSize, 0); Result = ProgressDialog->ProgressSynch.SetPosAndCheckPaused(0); if (Result != S_OK) return; } ProgressDialog->ProgressSynch.SetNumFilesTotal(NumFilesScan); ProgressDialog->ProgressSynch.SetProgress(totalSize, 0); DirEnumerator.Init(); for (;;) { NFile::NFind::CFileInfoW fileInfo; bool filled; UString resPath; if (!DirEnumerator.GetNextFile(fileInfo, filled, resPath, ErrorCode)) { ThereIsError = true; ErrorPath = resPath; return; } if (!filled) break; UInt32 crc = CRC_INIT_VAL; CSha256 sha256; Sha256_Init(&sha256); if (fileInfo.IsDir()) NumFolders++; else { NFile::NIO::CInFile inFile; if (!inFile.Open(DirEnumerator.BasePrefix + resPath)) { ErrorCode = ::GetLastError(); ThereIsError = true; ErrorPath = resPath; return; } ProgressDialog->ProgressSynch.SetCurrentFileName(resPath); ProgressDialog->ProgressSynch.SetNumFilesCur(NumFiles); NumFiles++; for (;;) { UInt32 processedSize; if (!inFile.Read(buffer, kBufSize, processedSize)) { ErrorCode = ::GetLastError(); ThereIsError = true; ErrorPath = resPath; return; } if (processedSize == 0) break; crc = CrcUpdate(crc, buffer, processedSize); if (NumFilesScan == 1) Sha256_Update(&sha256, buffer, processedSize); DataSize += processedSize; Result = ProgressDialog->ProgressSynch.SetPosAndCheckPaused(DataSize); if (Result != S_OK) return; } 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); Result = ProgressDialog->ProgressSynch.SetPosAndCheckPaused(DataSize); if (Result != S_OK) return; } } DWORD Process() { try { Process2(); } catch(...) { Error = L"Error"; ThereIsError = true;} ProgressDialog->MyClose(); return 0; } static THREAD_FUNC_DECL MyThreadFunction(void *param) { return ((CThreadCrc *)param)->Process(); } }; 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))); } } static void ConvertUInt32ToHex(UInt32 value, wchar_t *s) { for (int i = 6; i >= 0; i -= 2) { ConvertByteToHex(value & 0xFF, s + i); value >>= 8; } s[8] = L'\0'; } void CApp::CalculateCrc() { int srcPanelIndex = GetFocusedPanelIndex(); CPanel &srcPanel = Panels[srcPanelIndex]; if (!srcPanel.IsFSFolder()) { srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208); return; } CRecordVector indices; srcPanel.GetOperatedItemIndices(indices); if (indices.IsEmpty()) return; CThreadCrc combiner; for (int i = 0; i < indices.Size(); i++) combiner.DirEnumerator.FileNames.Add(srcPanel.GetItemRelPath(indices[i])); combiner.DirEnumerator.BasePrefix = srcPanel._currentFolderPrefix; combiner.DirEnumerator.FlatMode = GetFlatMode(); { CProgressDialog progressDialog; combiner.ProgressDialog = &progressDialog; combiner.ErrorCode = 0; combiner.Result = S_OK; combiner.ThereIsError = false; UString progressWindowTitle = LangString(IDS_APP_TITLE, 0x03000000); UString title = LangString(IDS_CHECKSUM_CALCULATING, 0x03020710); progressDialog.MainWindow = _window; progressDialog.MainTitle = progressWindowTitle; progressDialog.MainAddTitle = title + UString(L" "); NWindows::CThread thread; if (thread.Create(CThreadCrc::MyThreadFunction, &combiner) != S_OK) return; progressDialog.Create(title, _window); if (combiner.Result != S_OK) { if (combiner.Result != E_ABORT) srcPanel.MessageBoxError(combiner.Result); } else if (combiner.ThereIsError) { if (combiner.Error.IsEmpty()) { UString message = combiner.DirEnumerator.BasePrefix + combiner.ErrorPath; message += L"\n"; message += NError::MyFormatMessageW(combiner.ErrorCode); srcPanel.MessageBoxMyError(message); } else srcPanel.MessageBoxMyError(combiner.Error); } else { UString s; { wchar_t sz[32]; s += LangString(IDS_FILES_COLON, 0x02000320); s += L" "; ConvertUInt64ToString(combiner.NumFiles, sz); s += sz; s += L"\n"; s += LangString(IDS_FOLDERS_COLON, 0x02000321); s += L" "; ConvertUInt64ToString(combiner.NumFolders, sz); s += sz; s += L"\n"; s += LangString(IDS_SIZE_COLON, 0x02000322); s += L" "; ConvertUInt64ToString(combiner.DataSize, sz); s += MyFormatNew(IDS_FILE_SIZE, 0x02000982, sz);; s += L"\n"; s += LangString(IDS_CHECKSUM_CRC_DATA, 0x03020721); s += L" "; ConvertUInt32ToHex(combiner.DataCrcSum, sz); s += sz; s += L"\n"; s += LangString(IDS_CHECKSUM_CRC_DATA_NAMES, 0x03020722); s += L" "; ConvertUInt32ToHex(combiner.DataNameCrcSum, sz); s += sz; s += L"\n"; if (combiner.NumFiles == 1 && combiner.NumFilesScan == 1) { s += L"SHA-256: "; for (int i = 0; i < SHA256_DIGEST_SIZE; i++) { wchar_t s2[4]; ConvertByteToHex(combiner.Sha256Sum[i], s2); s2[2] = 0; s += s2; } } } srcPanel.MessageBoxInfo(s, LangString(IDS_CHECKSUM_INFORMATION, 0x03020720)); } } RefreshTitleAlways(); }