Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / UI / FileManager / PanelCrc.cpp
1 // PanelSplitFile.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "../../../../C/7zCrc.h"\r
6 #include "../../../../C/Sha256.h"\r
7 \r
8 #include "Common/IntToString.h"\r
9 \r
10 #include "Windows/FileFind.h"\r
11 #include "Windows/FileIO.h"\r
12 #include "Windows/FileName.h"\r
13 \r
14 #include "OverwriteDialogRes.h"\r
15 \r
16 #include "App.h"\r
17 #include "FormatUtils.h"\r
18 #include "LangUtils.h"\r
19 \r
20 #include "../Common/PropIDUtils.h"\r
21 \r
22 #include "resource.h"\r
23 \r
24 using namespace NWindows;\r
25 using namespace NFile;\r
26 \r
27 static const UInt32 kBufSize = (1 << 15);\r
28 \r
29 struct CDirEnumerator\r
30 {\r
31   bool FlatMode;\r
32   UString BasePrefix;\r
33   UStringVector FileNames;\r
34 \r
35   CObjectVector<NFind::CEnumeratorW> Enumerators;\r
36   UStringVector Prefixes;\r
37   int Index;\r
38   HRESULT GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &fullPath);\r
39   void Init();\r
40   \r
41   CDirEnumerator(): FlatMode(false) {};\r
42 };\r
43 \r
44 void CDirEnumerator::Init()\r
45 {\r
46   Enumerators.Clear();\r
47   Prefixes.Clear();\r
48   Index = 0;\r
49 }\r
50 \r
51 static HRESULT GetNormalizedError()\r
52 {\r
53   HRESULT errorCode = GetLastError();\r
54   return (errorCode == 0) ? E_FAIL : errorCode;\r
55 }\r
56 \r
57 HRESULT CDirEnumerator::GetNextFile(NFind::CFileInfoW &fileInfo, bool &filled, UString &resPath)\r
58 {\r
59   filled = false;\r
60   for (;;)\r
61   {\r
62     if (Enumerators.IsEmpty())\r
63     {\r
64       if (Index >= FileNames.Size())\r
65         return S_OK;\r
66       const UString &path = FileNames[Index];\r
67       int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR);\r
68       resPath.Empty();\r
69       if (pos >= 0)\r
70         resPath = path.Left(pos + 1);\r
71 \r
72       #ifdef _WIN32\r
73       // it's for "c:" paths/\r
74       if (BasePrefix.IsEmpty() && path.Length() == 2 && path[1] == ':')\r
75       {\r
76         fileInfo.Name = path;\r
77         fileInfo.Attrib = FILE_ATTRIBUTE_DIRECTORY;\r
78         fileInfo.Size = 0;\r
79       }\r
80       else\r
81       #endif\r
82       if (!fileInfo.Find(BasePrefix + path))\r
83       {\r
84         WRes errorCode = GetNormalizedError();\r
85         resPath = path;\r
86         return errorCode;\r
87       }\r
88       Index++;\r
89       break;\r
90     }\r
91     bool found;\r
92     if (!Enumerators.Back().Next(fileInfo, found))\r
93     {\r
94       HRESULT errorCode = GetNormalizedError();\r
95       resPath = Prefixes.Back();\r
96       return errorCode;\r
97     }\r
98     if (found)\r
99     {\r
100       resPath = Prefixes.Back();\r
101       break;\r
102     }\r
103     Enumerators.DeleteBack();\r
104     Prefixes.DeleteBack();\r
105   }\r
106   resPath += fileInfo.Name;\r
107   if (!FlatMode && fileInfo.IsDir())\r
108   {\r
109     UString prefix = resPath + WCHAR_PATH_SEPARATOR;\r
110     Enumerators.Add(NFind::CEnumeratorW(BasePrefix + prefix + (UString)(wchar_t)NName::kAnyStringWildcard));\r
111     Prefixes.Add(prefix);\r
112   }\r
113   filled = true;\r
114   return S_OK;\r
115 }\r
116 \r
117 static void ConvertByteToHex(unsigned value, wchar_t *s)\r
118 {\r
119   for (int i = 0; i < 2; i++)\r
120   {\r
121     unsigned t = value & 0xF;\r
122     value >>= 4;\r
123     s[1 - i] = (wchar_t)((t < 10) ? (L'0' + t) : (L'A' + (t - 10)));\r
124   }\r
125 }\r
126 \r
127 class CThreadCrc: public CProgressThreadVirt\r
128 {\r
129   UInt64 NumFilesScan;\r
130   UInt64 NumFiles;\r
131   UInt64 NumFolders;\r
132   UInt64 DataSize;\r
133   UInt32 DataCrcSum;\r
134   Byte Sha256Sum[SHA256_DIGEST_SIZE];\r
135   UInt32 DataNameCrcSum;\r
136 \r
137   UString GetResultMessage() const;\r
138   HRESULT ProcessVirt();\r
139 public:\r
140   CDirEnumerator Enumerator;\r
141  \r
142 };\r
143 \r
144 UString CThreadCrc::GetResultMessage() const\r
145 {\r
146   UString s;\r
147   wchar_t sz[32];\r
148   \r
149   s += LangString(IDS_FILES_COLON, 0x02000320);\r
150   s += L' ';\r
151   ConvertUInt64ToString(NumFiles, sz);\r
152   s += sz;\r
153   s += L'\n';\r
154   \r
155   s += LangString(IDS_FOLDERS_COLON, 0x02000321);\r
156   s += L' ';\r
157   ConvertUInt64ToString(NumFolders, sz);\r
158   s += sz;\r
159   s += L'\n';\r
160   \r
161   s += LangString(IDS_SIZE_COLON, 0x02000322);\r
162   s += L' ';\r
163   ConvertUInt64ToString(DataSize, sz);\r
164   s += MyFormatNew(IDS_FILE_SIZE, 0x02000982, sz);\r
165   s += L'\n';\r
166   \r
167   s += LangString(IDS_CHECKSUM_CRC_DATA, 0x03020721);\r
168   s += L' ';\r
169   ConvertUInt32ToHex(DataCrcSum, sz);\r
170   s += sz;\r
171   s += L'\n';\r
172   \r
173   s += LangString(IDS_CHECKSUM_CRC_DATA_NAMES, 0x03020722);\r
174   s += L' ';\r
175   ConvertUInt32ToHex(DataNameCrcSum, sz);\r
176   s += sz;\r
177   s += L'\n';\r
178   \r
179   if (NumFiles == 1 && NumFilesScan == 1)\r
180   {\r
181     s += L"SHA-256: ";\r
182     for (int i = 0; i < SHA256_DIGEST_SIZE; i++)\r
183     {\r
184       wchar_t s2[4];\r
185       ConvertByteToHex(Sha256Sum[i], s2);\r
186       s2[2] = 0;\r
187       s += s2;\r
188     }\r
189   }\r
190   return s;\r
191 }\r
192 \r
193 HRESULT CThreadCrc::ProcessVirt()\r
194 {\r
195   DataSize = NumFolders = NumFiles = NumFilesScan = DataCrcSum = DataNameCrcSum = 0;\r
196   memset(Sha256Sum, 0, SHA256_DIGEST_SIZE);\r
197   // ProgressDialog.WaitCreating();\r
198   \r
199   CMyBuffer bufferObject;\r
200   if (!bufferObject.Allocate(kBufSize))\r
201     return E_OUTOFMEMORY;\r
202   Byte *buffer = (Byte *)(void *)bufferObject;\r
203   \r
204   UInt64 totalSize = 0;\r
205   \r
206   Enumerator.Init();\r
207   \r
208   UString scanningStr = LangString(IDS_SCANNING, 0x03020800);\r
209   scanningStr += L' ';\r
210   \r
211   CProgressSync &sync = ProgressDialog.Sync;\r
212 \r
213   for (;;)\r
214   {\r
215     NFind::CFileInfoW fileInfo;\r
216     bool filled;\r
217     UString resPath;\r
218     HRESULT errorCode = Enumerator.GetNextFile(fileInfo, filled, resPath);\r
219     if (errorCode != 0)\r
220     {\r
221       ErrorPath1 = resPath;\r
222       return errorCode;\r
223     }\r
224     if (!filled)\r
225       break;\r
226     if (!fileInfo.IsDir())\r
227     {\r
228       totalSize += fileInfo.Size;\r
229       NumFilesScan++;\r
230     }\r
231     sync.SetCurrentFileName(scanningStr + resPath);\r
232     sync.SetProgress(totalSize, 0);\r
233     RINOK(sync.SetPosAndCheckPaused(0));\r
234   }\r
235   sync.SetNumFilesTotal(NumFilesScan);\r
236   sync.SetProgress(totalSize, 0);\r
237   \r
238   Enumerator.Init();\r
239   \r
240   for (;;)\r
241   {\r
242     NFind::CFileInfoW fileInfo;\r
243     bool filled;\r
244     UString resPath;\r
245     HRESULT errorCode = Enumerator.GetNextFile(fileInfo, filled, resPath);\r
246     if (errorCode != 0)\r
247     {\r
248       ErrorPath1 = resPath;\r
249       return errorCode;\r
250     }\r
251     if (!filled)\r
252       break;\r
253     \r
254     UInt32 crc = CRC_INIT_VAL;\r
255     CSha256 sha256;\r
256     Sha256_Init(&sha256);\r
257     \r
258     if (fileInfo.IsDir())\r
259       NumFolders++;\r
260     else\r
261     {\r
262       NIO::CInFile inFile;\r
263       if (!inFile.Open(Enumerator.BasePrefix + resPath))\r
264       {\r
265         errorCode = GetNormalizedError();\r
266         ErrorPath1 = resPath;\r
267         return errorCode;\r
268       }\r
269       sync.SetCurrentFileName(resPath);\r
270       sync.SetNumFilesCur(NumFiles);\r
271       NumFiles++;\r
272       for (;;)\r
273       {\r
274         UInt32 processedSize;\r
275         if (!inFile.Read(buffer, kBufSize, processedSize))\r
276         {\r
277           errorCode = GetNormalizedError();\r
278           ErrorPath1 = resPath;\r
279           return errorCode;\r
280         }\r
281         if (processedSize == 0)\r
282           break;\r
283         crc = CrcUpdate(crc, buffer, processedSize);\r
284         if (NumFilesScan == 1)\r
285           Sha256_Update(&sha256, buffer, processedSize);\r
286         \r
287         DataSize += processedSize;\r
288         RINOK(sync.SetPosAndCheckPaused(DataSize));\r
289       }\r
290       DataCrcSum += CRC_GET_DIGEST(crc);\r
291       if (NumFilesScan == 1)\r
292         Sha256_Final(&sha256, Sha256Sum);\r
293     }\r
294     for (int i = 0; i < resPath.Length(); i++)\r
295     {\r
296       wchar_t c = resPath[i];\r
297       crc = CRC_UPDATE_BYTE(crc, ((Byte)(c & 0xFF)));\r
298       crc = CRC_UPDATE_BYTE(crc, ((Byte)((c >> 8) & 0xFF)));\r
299     }\r
300     DataNameCrcSum += CRC_GET_DIGEST(crc);\r
301     RINOK(sync.SetPosAndCheckPaused(DataSize));\r
302   }\r
303   sync.SetNumFilesCur(NumFiles);\r
304   OkMessage = GetResultMessage();\r
305   OkMessageTitle = LangString(IDS_CHECKSUM_INFORMATION, 0x03020720);\r
306   return S_OK;\r
307 }\r
308 \r
309 void CApp::CalculateCrc()\r
310 {\r
311   int srcPanelIndex = GetFocusedPanelIndex();\r
312   CPanel &srcPanel = Panels[srcPanelIndex];\r
313   if (!srcPanel.IsFsOrDrivesFolder())\r
314   {\r
315     srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
316     return;\r
317   }\r
318   CRecordVector<UInt32> indices;\r
319   srcPanel.GetOperatedItemIndices(indices);\r
320   if (indices.IsEmpty())\r
321     return;\r
322 \r
323   {\r
324   CThreadCrc t;\r
325   for (int i = 0; i < indices.Size(); i++)\r
326     t.Enumerator.FileNames.Add(srcPanel.GetItemRelPath(indices[i]));\r
327   t.Enumerator.BasePrefix = srcPanel.GetFsPath();\r
328   t.Enumerator.FlatMode = GetFlatMode();\r
329 \r
330   t.ProgressDialog.ShowCompressionInfo = false;\r
331 \r
332   UString title = LangString(IDS_CHECKSUM_CALCULATING, 0x03020710);\r
333 \r
334   t.ProgressDialog.MainWindow = _window;\r
335   t.ProgressDialog.MainTitle = LangString(IDS_APP_TITLE, 0x03000000);\r
336   t.ProgressDialog.MainAddTitle = title + UString(L' ');\r
337 \r
338   if (t.Create(title, _window) != S_OK)\r
339     return;\r
340   }\r
341   RefreshTitleAlways();\r
342 }\r