| // 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<NFind::CEnumeratorW> 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<UInt32> 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(); |
| } |