OSDN Git Service

add japanese site html
[sevenzip/7-Zip.git] / 7z457 / CPP / 7zip / UI / FileManager / PanelCrc.cpp
1 // PanelSplitFile.cpp
2
3 #include "StdAfx.h"
4
5 #include "resource.h"
6
7 extern "C" 
8
9   #include "../../../../C/Alloc.h"
10   #include "../../../../C/7zCrc.h"
11 }
12
13 #include "Common/IntToString.h"
14 #include "Common/StringConvert.h"
15
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"
21
22 #include "ProgressDialog2.h"
23 #include "OverwriteDialogRes.h"
24
25 #include "App.h"
26 #include "FormatUtils.h"
27 #include "LangUtils.h"
28
29 using namespace NWindows;
30 using namespace NFile;
31 using namespace NName;
32
33 static const UInt32 kBufSize = (1 << 15);
34
35 struct CDirEnumerator
36 {
37   bool FlatMode;
38   UString BasePrefix;
39   UStringVector FileNames;
40
41   CObjectVector<NFind::CEnumeratorW> Enumerators;
42   UStringVector Prefixes;
43   int Index;
44   bool GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &fullPath, DWORD &errorCode);
45   void Init();
46   
47   CDirEnumerator(): FlatMode(false) {};
48 };
49
50 void CDirEnumerator::Init()
51 {
52   Enumerators.Clear();
53   Prefixes.Clear();
54   Index = 0;
55 }
56
57 bool CDirEnumerator::GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &resPath, DWORD &errorCode)
58 {
59   filled = false;
60   for (;;)
61   {
62     if (Enumerators.IsEmpty())
63     {
64       if (Index >= FileNames.Size())
65         return true;
66       const UString &path = FileNames[Index];
67       int pos = path.ReverseFind('\\');
68       resPath.Empty();
69       if (pos >= 0)
70         resPath = path.Left(pos + 1);
71       if (!NFind::FindFile(BasePrefix + path, fileInfo))
72       {
73         errorCode = ::GetLastError();
74         resPath = path;
75         return false;
76       }
77       Index++;
78       break;
79     }
80     bool found;
81     if (!Enumerators.Back().Next(fileInfo, found))
82     {
83       errorCode = ::GetLastError();
84       resPath = Prefixes.Back();
85       return false;
86     }
87     if (found)
88     {
89       resPath = Prefixes.Back();
90       break;
91     }
92     Enumerators.DeleteBack();
93     Prefixes.DeleteBack();
94   }
95   resPath += fileInfo.Name;
96   if (!FlatMode && fileInfo.IsDirectory())
97   {
98     UString prefix = resPath + (UString)(wchar_t)kDirDelimiter;
99     Enumerators.Add(NFind::CEnumeratorW(BasePrefix + prefix + (UString)(wchar_t)kAnyStringWildcard));
100     Prefixes.Add(prefix);
101   }
102   filled = true;
103   return true;
104 }
105
106 struct CThreadCrc
107 {
108   class CMyBuffer
109   {
110     void *_data;
111   public:
112     CMyBuffer(): _data(0) {}
113     operator void *() { return _data; }
114     bool Allocate(size_t size)
115     {
116       if (_data != 0)
117         return false;
118       _data = ::MidAlloc(size);
119       return _data != 0;
120     }
121     ~CMyBuffer() { ::MidFree(_data); }
122   };
123
124   CProgressDialog *ProgressDialog;
125
126   CDirEnumerator DirEnumerator;
127   
128   UInt64 NumFiles;
129   UInt64 NumFolders;
130   UInt64 DataSize;
131   UInt32 DataCrcSum;
132   UInt32 DataNameCrcSum;
133
134   HRESULT Result;
135   DWORD ErrorCode;
136   UString ErrorPath;
137   UString Error;
138   bool ThereIsError;
139   
140   void Process2()
141   {
142     DataSize = NumFolders = NumFiles = DataCrcSum = DataNameCrcSum = 0;
143     ProgressDialog->WaitCreating();
144
145     CMyBuffer bufferObject;
146     if (!bufferObject.Allocate(kBufSize))
147     {
148       Error = L"Can not allocate memory";
149       ThereIsError = true;
150       return;
151     }
152     Byte *buffer = (Byte *)(void *)bufferObject;
153
154     UInt64 totalSize = 0;
155
156     DirEnumerator.Init();
157
158     UString scanningStr = LangString(IDS_SCANNING, 0x03020800);
159     scanningStr += L" ";
160
161     for (;;)
162     {
163       NFile::NFind::CFileInfoW fileInfo;
164       bool filled;
165       UString resPath;
166       if (!DirEnumerator.GetNextFile(fileInfo, filled, resPath, ErrorCode))
167       {
168         ThereIsError = true;
169         ErrorPath = resPath;
170         return;
171       }
172       if (!filled)
173         break;
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);
179       if (Result != S_OK)
180         return;
181     }
182
183     ProgressDialog->ProgressSynch.SetProgress(totalSize, 0);
184
185     DirEnumerator.Init();
186
187     for (;;)
188     {
189       NFile::NFind::CFileInfoW fileInfo;
190       bool filled;
191       UString resPath;
192       if (!DirEnumerator.GetNextFile(fileInfo, filled, resPath, ErrorCode))
193       {
194         ThereIsError = true;
195         ErrorPath = resPath;
196         return;
197       }
198       if (!filled)
199         break;
200
201       UInt32 crc = CRC_INIT_VAL;
202       if (fileInfo.IsDirectory())
203         NumFolders++;
204       else
205       {
206         NFile::NIO::CInFile inFile;
207         if (!inFile.Open(DirEnumerator.BasePrefix + resPath))
208         {
209           ErrorCode = ::GetLastError();
210           ThereIsError = true;
211           ErrorPath = resPath;
212           return;
213         }
214         NumFiles++;
215         ProgressDialog->ProgressSynch.SetCurrentFileName(resPath);
216         for (;;)
217         {
218           UInt32 processedSize;
219           if (!inFile.Read(buffer, kBufSize, processedSize))
220           {
221             ErrorCode = ::GetLastError();
222             ThereIsError = true;
223             ErrorPath = resPath;
224             return;
225           }
226           if (processedSize == 0)
227             break;
228           crc = CrcUpdate(crc, buffer, processedSize);
229           DataSize += processedSize;
230           Result = ProgressDialog->ProgressSynch.SetPosAndCheckPaused(DataSize);
231           if (Result != S_OK)
232             return;
233         }
234         DataCrcSum += CRC_GET_DIGEST(crc);
235       }
236       for (int i = 0; i < resPath.Length(); i++)
237       {
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)));
241       }
242       DataNameCrcSum += CRC_GET_DIGEST(crc);
243       Result = ProgressDialog->ProgressSynch.SetPosAndCheckPaused(DataSize);
244       if (Result != S_OK)
245         return;
246     }
247   }
248   DWORD Process()
249   {
250     try { Process2(); }
251     catch(...) { Error = L"Error"; ThereIsError = true;}
252     ProgressDialog->MyClose();
253     return 0;
254   }
255   
256   static THREAD_FUNC_DECL MyThreadFunction(void *param)
257   {
258     return ((CThreadCrc *)param)->Process();
259   }
260 };
261
262 static void ConvertUInt32ToHex(UInt32 value, wchar_t *s)
263 {
264   for (int i = 0; i < 8; i++)
265   {
266     int t = value & 0xF;
267     value >>= 4;
268     s[7 - i] = (wchar_t)((t < 10) ? (L'0' + t) : (L'A' + (t - 10)));
269   }
270   s[8] = L'\0';
271 }
272
273 void CApp::CalculateCrc()
274 {
275   int srcPanelIndex = GetFocusedPanelIndex();
276   CPanel &srcPanel = Panels[srcPanelIndex];
277   if (!srcPanel.IsFSFolder())
278   {
279     srcPanel.MessageBox(LangString(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208));
280     return;
281   }
282   CRecordVector<UInt32> indices;
283   srcPanel.GetOperatedItemIndices(indices);
284   if (indices.IsEmpty())
285     return;
286
287   CThreadCrc combiner;
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();
292
293   {
294   CProgressDialog progressDialog;
295   combiner.ProgressDialog = &progressDialog;
296   combiner.ErrorCode = 0;
297   combiner.Result = S_OK;
298   combiner.ThereIsError = false;
299
300   UString progressWindowTitle = LangString(IDS_APP_TITLE, 0x03000000);
301   UString title = LangString(IDS_CHECKSUM_CALCULATING, 0x03020710);
302
303   progressDialog.MainWindow = _window;
304   progressDialog.MainTitle = progressWindowTitle;
305   progressDialog.MainAddTitle = title + UString(L" ");
306
307   NWindows::CThread thread;
308   if (thread.Create(CThreadCrc::MyThreadFunction, &combiner) != S_OK)
309     return;
310   progressDialog.Create(title, _window);
311
312   if (combiner.Result != S_OK)
313   {
314     if (combiner.Result != E_ABORT)
315       srcPanel.MessageBoxError(combiner.Result);
316   }
317   else if (combiner.ThereIsError)
318   {
319     if (combiner.Error.IsEmpty())
320     {
321       UString message = combiner.DirEnumerator.BasePrefix + combiner.ErrorPath;
322       message += L"\n";
323       message += NError::MyFormatMessageW(combiner.ErrorCode);
324       srcPanel.MessageBoxMyError(message);
325     }
326     else
327       srcPanel.MessageBoxMyError(combiner.Error);
328   }
329   else
330   {
331     UString s;
332     {
333       wchar_t sz[32];
334
335       s += LangString(IDS_FILES_COLON, 0x02000320);
336       s += L" ";
337       ConvertUInt64ToString(combiner.NumFiles, sz);
338       s += sz;
339       s += L"\n";
340       
341       s += LangString(IDS_FOLDERS_COLON, 0x02000321);
342       s += L" ";
343       ConvertUInt64ToString(combiner.NumFolders, sz);
344       s += sz;
345       s += L"\n";
346
347       s += LangString(IDS_SIZE_COLON, 0x02000322);
348       s += L" ";
349       ConvertUInt64ToString(combiner.DataSize, sz);
350       s += MyFormatNew(IDS_FILE_SIZE, 0x02000982, sz);;
351       s += L"\n";
352
353       s += LangString(IDS_CHECKSUM_CRC_DATA, 0x03020721);
354       s += L" ";
355       ConvertUInt32ToHex(combiner.DataCrcSum, sz);
356       s += sz;
357       s += L"\n";
358
359       s += LangString(IDS_CHECKSUM_CRC_DATA_NAMES, 0x03020722);
360       s += L" ";
361       ConvertUInt32ToHex(combiner.DataNameCrcSum, sz);
362       s += sz;
363     }
364     srcPanel.MessageBoxInfo(s, LangString(IDS_CHECKSUM_INFORMATION, 0x03020720));
365   }
366   }
367   RefreshTitleAlways();
368 }