9 #include "../../../../C/Alloc.h"
10 #include "../../../../C/7zCrc.h"
13 #include "Common/IntToString.h"
14 #include "Common/StringConvert.h"
16 #include "Windows/FileIO.h"
17 #include "Windows/FileFind.h"
18 #include "Windows/FileName.h"
19 #include "Windows/Thread.h"
20 #include "Windows/Error.h"
22 #include "ProgressDialog2.h"
23 #include "OverwriteDialogRes.h"
26 #include "FormatUtils.h"
27 #include "LangUtils.h"
29 using namespace NWindows;
30 using namespace NFile;
31 using namespace NName;
33 static const UInt32 kBufSize = (1 << 15);
39 UStringVector FileNames;
41 CObjectVector<NFind::CEnumeratorW> Enumerators;
42 UStringVector Prefixes;
44 bool GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &fullPath, DWORD &errorCode);
47 CDirEnumerator(): FlatMode(false) {};
50 void CDirEnumerator::Init()
57 bool CDirEnumerator::GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &resPath, DWORD &errorCode)
62 if (Enumerators.IsEmpty())
64 if (Index >= FileNames.Size())
66 const UString &path = FileNames[Index];
67 int pos = path.ReverseFind('\\');
70 resPath = path.Left(pos + 1);
71 if (!NFind::FindFile(BasePrefix + path, fileInfo))
73 errorCode = ::GetLastError();
81 if (!Enumerators.Back().Next(fileInfo, found))
83 errorCode = ::GetLastError();
84 resPath = Prefixes.Back();
89 resPath = Prefixes.Back();
92 Enumerators.DeleteBack();
93 Prefixes.DeleteBack();
95 resPath += fileInfo.Name;
96 if (!FlatMode && fileInfo.IsDirectory())
98 UString prefix = resPath + (UString)(wchar_t)kDirDelimiter;
99 Enumerators.Add(NFind::CEnumeratorW(BasePrefix + prefix + (UString)(wchar_t)kAnyStringWildcard));
100 Prefixes.Add(prefix);
112 CMyBuffer(): _data(0) {}
113 operator void *() { return _data; }
114 bool Allocate(size_t size)
118 _data = ::MidAlloc(size);
121 ~CMyBuffer() { ::MidFree(_data); }
124 CProgressDialog *ProgressDialog;
126 CDirEnumerator DirEnumerator;
132 UInt32 DataNameCrcSum;
142 DataSize = NumFolders = NumFiles = DataCrcSum = DataNameCrcSum = 0;
143 ProgressDialog->WaitCreating();
145 CMyBuffer bufferObject;
146 if (!bufferObject.Allocate(kBufSize))
148 Error = L"Can not allocate memory";
152 Byte *buffer = (Byte *)(void *)bufferObject;
154 UInt64 totalSize = 0;
156 DirEnumerator.Init();
158 UString scanningStr = LangString(IDS_SCANNING, 0x03020800);
163 NFile::NFind::CFileInfoW fileInfo;
166 if (!DirEnumerator.GetNextFile(fileInfo, filled, resPath, ErrorCode))
174 if (!fileInfo.IsDirectory())
175 totalSize += fileInfo.Size;
176 ProgressDialog->ProgressSynch.SetCurrentFileName(scanningStr + resPath);
177 ProgressDialog->ProgressSynch.SetProgress(totalSize, 0);
178 Result = ProgressDialog->ProgressSynch.SetPosAndCheckPaused(0);
183 ProgressDialog->ProgressSynch.SetProgress(totalSize, 0);
185 DirEnumerator.Init();
189 NFile::NFind::CFileInfoW fileInfo;
192 if (!DirEnumerator.GetNextFile(fileInfo, filled, resPath, ErrorCode))
201 UInt32 crc = CRC_INIT_VAL;
202 if (fileInfo.IsDirectory())
206 NFile::NIO::CInFile inFile;
207 if (!inFile.Open(DirEnumerator.BasePrefix + resPath))
209 ErrorCode = ::GetLastError();
215 ProgressDialog->ProgressSynch.SetCurrentFileName(resPath);
218 UInt32 processedSize;
219 if (!inFile.Read(buffer, kBufSize, processedSize))
221 ErrorCode = ::GetLastError();
226 if (processedSize == 0)
228 crc = CrcUpdate(crc, buffer, processedSize);
229 DataSize += processedSize;
230 Result = ProgressDialog->ProgressSynch.SetPosAndCheckPaused(DataSize);
234 DataCrcSum += CRC_GET_DIGEST(crc);
236 for (int i = 0; i < resPath.Length(); i++)
238 wchar_t c = resPath[i];
239 crc = CRC_UPDATE_BYTE(crc, ((Byte)(c & 0xFF)));
240 crc = CRC_UPDATE_BYTE(crc, ((Byte)((c >> 8) & 0xFF)));
242 DataNameCrcSum += CRC_GET_DIGEST(crc);
243 Result = ProgressDialog->ProgressSynch.SetPosAndCheckPaused(DataSize);
251 catch(...) { Error = L"Error"; ThereIsError = true;}
252 ProgressDialog->MyClose();
256 static THREAD_FUNC_DECL MyThreadFunction(void *param)
258 return ((CThreadCrc *)param)->Process();
262 static void ConvertUInt32ToHex(UInt32 value, wchar_t *s)
264 for (int i = 0; i < 8; i++)
268 s[7 - i] = (wchar_t)((t < 10) ? (L'0' + t) : (L'A' + (t - 10)));
273 void CApp::CalculateCrc()
275 int srcPanelIndex = GetFocusedPanelIndex();
276 CPanel &srcPanel = Panels[srcPanelIndex];
277 if (!srcPanel.IsFSFolder())
279 srcPanel.MessageBox(LangString(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208));
282 CRecordVector<UInt32> indices;
283 srcPanel.GetOperatedItemIndices(indices);
284 if (indices.IsEmpty())
288 for (int i = 0; i < indices.Size(); i++)
289 combiner.DirEnumerator.FileNames.Add(srcPanel.GetItemRelPath(indices[i]));
290 combiner.DirEnumerator.BasePrefix = srcPanel._currentFolderPrefix;
291 combiner.DirEnumerator.FlatMode = GetFlatMode();
294 CProgressDialog progressDialog;
295 combiner.ProgressDialog = &progressDialog;
296 combiner.ErrorCode = 0;
297 combiner.Result = S_OK;
298 combiner.ThereIsError = false;
300 UString progressWindowTitle = LangString(IDS_APP_TITLE, 0x03000000);
301 UString title = LangString(IDS_CHECKSUM_CALCULATING, 0x03020710);
303 progressDialog.MainWindow = _window;
304 progressDialog.MainTitle = progressWindowTitle;
305 progressDialog.MainAddTitle = title + UString(L" ");
307 NWindows::CThread thread;
308 if (thread.Create(CThreadCrc::MyThreadFunction, &combiner) != S_OK)
310 progressDialog.Create(title, _window);
312 if (combiner.Result != S_OK)
314 if (combiner.Result != E_ABORT)
315 srcPanel.MessageBoxError(combiner.Result);
317 else if (combiner.ThereIsError)
319 if (combiner.Error.IsEmpty())
321 UString message = combiner.DirEnumerator.BasePrefix + combiner.ErrorPath;
323 message += NError::MyFormatMessageW(combiner.ErrorCode);
324 srcPanel.MessageBoxMyError(message);
327 srcPanel.MessageBoxMyError(combiner.Error);
335 s += LangString(IDS_FILES_COLON, 0x02000320);
337 ConvertUInt64ToString(combiner.NumFiles, sz);
341 s += LangString(IDS_FOLDERS_COLON, 0x02000321);
343 ConvertUInt64ToString(combiner.NumFolders, sz);
347 s += LangString(IDS_SIZE_COLON, 0x02000322);
349 ConvertUInt64ToString(combiner.DataSize, sz);
350 s += MyFormatNew(IDS_FILE_SIZE, 0x02000982, sz);;
353 s += LangString(IDS_CHECKSUM_CRC_DATA, 0x03020721);
355 ConvertUInt32ToHex(combiner.DataCrcSum, sz);
359 s += LangString(IDS_CHECKSUM_CRC_DATA_NAMES, 0x03020722);
361 ConvertUInt32ToHex(combiner.DataNameCrcSum, sz);
364 srcPanel.MessageBoxInfo(s, LangString(IDS_CHECKSUM_INFORMATION, 0x03020720));
367 RefreshTitleAlways();