xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/FileManager/PanelCrc.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // PanelCrc.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/MyException.h"
6 
7 #include "../../../Windows/FileFind.h"
8 #include "../../../Windows/FileIO.h"
9 #include "../../../Windows/FileName.h"
10 
11 #include "../Common/LoadCodecs.h"
12 
13 #include "../GUI/HashGUI.h"
14 
15 #include "App.h"
16 #include "LangUtils.h"
17 
18 #include "resource.h"
19 
20 using namespace NWindows;
21 using namespace NFile;
22 
23 #ifdef Z7_EXTERNAL_CODECS
24 extern CExternalCodecs g_ExternalCodecs;
25 HRESULT LoadGlobalCodecs();
26 #endif
27 
28 static const UInt32 kBufSize = (1 << 15);
29 
30 struct CDirEnumerator
31 {
32   bool EnterToDirs;
33   FString BasePrefix;
34   FString BasePrefix_for_Open;
35   FStringVector FilePaths;
36 
37   CObjectVector<NFind::CEnumerator> Enumerators;
38   FStringVector Prefixes;
39   unsigned Index;
40 
CDirEnumeratorCDirEnumerator41   CDirEnumerator(): EnterToDirs(false), Index(0) {}
42 
43   void Init();
44   DWORD GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath);
45 };
46 
Init()47 void CDirEnumerator::Init()
48 {
49   Enumerators.Clear();
50   Prefixes.Clear();
51   Index = 0;
52 }
53 
GetNormalizedError()54 static DWORD GetNormalizedError()
55 {
56   const DWORD error = GetLastError();
57   return (error == 0) ? (DWORD)E_FAIL : error;
58 }
59 
GetNextFile(NFind::CFileInfo & fi,bool & filled,FString & resPath)60 DWORD CDirEnumerator::GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath)
61 {
62   filled = false;
63   resPath.Empty();
64 
65   for (;;)
66   {
67     #if defined(_WIN32) && !defined(UNDER_CE)
68     bool isRootPrefix = (BasePrefix.IsEmpty() || (NName::IsSuperPath(BasePrefix) && BasePrefix[NName::kSuperPathPrefixSize] == 0));
69     #endif
70 
71     if (Enumerators.IsEmpty())
72     {
73       if (Index >= FilePaths.Size())
74         return S_OK;
75       const FString &path = FilePaths[Index++];
76       const int pos = path.ReverseFind_PathSepar();
77       if (pos >= 0)
78         resPath.SetFrom(path, (unsigned)pos + 1);
79 
80       #if defined(_WIN32) && !defined(UNDER_CE)
81       if (isRootPrefix && path.Len() == 2 && NName::IsDrivePath2(path))
82       {
83         // we use "c:" item as directory item
84         fi.ClearBase();
85         fi.Name = path;
86         fi.SetAsDir();
87         fi.Size = 0;
88       }
89       else
90       #endif
91       if (!fi.Find(BasePrefix + path))
92       {
93         const DWORD error = GetNormalizedError();
94         resPath = path;
95         return error;
96       }
97 
98       break;
99     }
100 
101     bool found;
102 
103     if (Enumerators.Back().Next(fi, found))
104     {
105       if (found)
106       {
107         resPath = Prefixes.Back();
108         break;
109       }
110     }
111     else
112     {
113       const DWORD error = GetNormalizedError();
114       resPath = Prefixes.Back();
115       Enumerators.DeleteBack();
116       Prefixes.DeleteBack();
117       return error;
118     }
119 
120     Enumerators.DeleteBack();
121     Prefixes.DeleteBack();
122   }
123 
124   resPath += fi.Name;
125 
126   if (EnterToDirs && fi.IsDir())
127   {
128     FString s = resPath;
129     s.Add_PathSepar();
130     Prefixes.Add(s);
131     Enumerators.AddNew().SetDirPrefix(BasePrefix + s);
132   }
133 
134   filled = true;
135   return S_OK;
136 }
137 
138 
139 
140 class CThreadCrc: public CProgressThreadVirt
141 {
142   bool ResultsWereShown;
143   bool WasFinished;
144 
145   HRESULT ProcessVirt() Z7_override;
146   virtual void ProcessWasFinished_GuiVirt() Z7_override;
147 public:
148   CDirEnumerator Enumerator;
149   CHashBundle Hash;
150   // FString FirstFilePath;
151 
152   void SetStatus(const UString &s);
153   void AddErrorMessage(DWORD systemError, const FChar *name);
154   void ShowFinalResults(HWND hwnd);
155 
CThreadCrc()156   CThreadCrc():
157     ResultsWereShown(false),
158     WasFinished(false)
159     {}
160 };
161 
ShowFinalResults(HWND hwnd)162 void CThreadCrc::ShowFinalResults(HWND hwnd)
163 {
164   if (WasFinished)
165   if (!ResultsWereShown)
166   {
167     ResultsWereShown = true;
168     ShowHashResults(Hash, hwnd);
169   }
170 }
171 
ProcessWasFinished_GuiVirt()172 void CThreadCrc::ProcessWasFinished_GuiVirt()
173 {
174   ShowFinalResults(*this);
175 }
176 
AddErrorMessage(DWORD systemError,const FChar * name)177 void CThreadCrc::AddErrorMessage(DWORD systemError, const FChar *name)
178 {
179   Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(Enumerator.BasePrefix + name));
180   Hash.NumErrors++;
181 }
182 
SetStatus(const UString & s2)183 void CThreadCrc::SetStatus(const UString &s2)
184 {
185   UString s = s2;
186   if (!Enumerator.BasePrefix.IsEmpty())
187   {
188     s.Add_Space_if_NotEmpty();
189     s += fs2us(Enumerator.BasePrefix);
190   }
191   Sync.Set_Status(s);
192 }
193 
ProcessVirt()194 HRESULT CThreadCrc::ProcessVirt()
195 {
196   // Hash.Init();
197 
198   CMyBuffer buf;
199   if (!buf.Allocate(kBufSize))
200     return E_OUTOFMEMORY;
201 
202   CProgressSync &sync = Sync;
203 
204   SetStatus(LangString(IDS_SCANNING));
205 
206   Enumerator.Init();
207 
208   FString path;
209   NFind::CFileInfo fi;
210   UInt64 numFiles = 0;
211   UInt64 numItems = 0, numItems_Prev = 0;
212   UInt64 totalSize = 0;
213 
214   for (;;)
215   {
216     bool filled;
217     const DWORD error = Enumerator.GetNextFile(fi, filled, path);
218     if (error != 0)
219     {
220       AddErrorMessage(error, path);
221       continue;
222     }
223     if (!filled)
224       break;
225     if (!fi.IsDir())
226     {
227       totalSize += fi.Size;
228       numFiles++;
229     }
230     numItems++;
231     bool needPrint = false;
232     // if (fi.IsDir())
233     {
234       if (numItems - numItems_Prev >= 100)
235       {
236         needPrint = true;
237         numItems_Prev = numItems;
238       }
239     }
240     /*
241     else if (numFiles - numFiles_Prev >= 200)
242     {
243       needPrint = true;
244       numFiles_Prev = numFiles;
245     }
246     */
247     if (needPrint)
248     {
249       RINOK(sync.ScanProgress(numFiles, totalSize, path, fi.IsDir()))
250     }
251   }
252   RINOK(sync.ScanProgress(numFiles, totalSize, FString(), false))
253   // sync.SetNumFilesTotal(numFiles);
254   // sync.SetProgress(totalSize, 0);
255   // SetStatus(LangString(IDS_CHECKSUM_CALCULATING));
256   // sync.SetCurFilePath(L"");
257   SetStatus(L"");
258 
259   Enumerator.Init();
260 
261   FString tempPath;
262   bool isFirstFile = true;
263   UInt64 errorsFilesSize = 0;
264 
265   for (;;)
266   {
267     bool filled;
268     DWORD error = Enumerator.GetNextFile(fi, filled, path);
269     if (error != 0)
270     {
271       AddErrorMessage(error, path);
272       continue;
273     }
274     if (!filled)
275       break;
276 
277     error = 0;
278     Hash.InitForNewFile();
279     if (!fi.IsDir())
280     {
281       NIO::CInFile inFile;
282       tempPath = Enumerator.BasePrefix_for_Open;
283       tempPath += path;
284       if (!inFile.Open(tempPath))
285       {
286         error = GetNormalizedError();
287         AddErrorMessage(error, path);
288         continue;
289       }
290       if (isFirstFile)
291       {
292         Hash.FirstFileName = fs2us(path);
293         isFirstFile = false;
294       }
295       sync.Set_FilePath(fs2us(path));
296       sync.Set_NumFilesCur(Hash.NumFiles);
297       UInt64 progress_Prev = 0;
298       for (;;)
299       {
300         UInt32 size;
301         if (!inFile.Read(buf, kBufSize, size))
302         {
303           error = GetNormalizedError();
304           AddErrorMessage(error, path);
305           UInt64 errorSize = 0;
306           if (inFile.GetLength(errorSize))
307             errorsFilesSize += errorSize;
308           break;
309         }
310         if (size == 0)
311           break;
312         Hash.Update(buf, size);
313         if (Hash.CurSize - progress_Prev >= ((UInt32)1 << 21))
314         {
315           RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize + Hash.CurSize))
316           progress_Prev = Hash.CurSize;
317         }
318       }
319     }
320     if (error == 0)
321       Hash.Final(fi.IsDir(), false, fs2us(path));
322     RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize))
323   }
324   RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize))
325   sync.Set_NumFilesCur(Hash.NumFiles);
326   if (Hash.NumFiles != 1)
327     sync.Set_FilePath(L"");
328   SetStatus(L"");
329 
330   CProgressMessageBoxPair &pair = GetMessagePair(Hash.NumErrors != 0);
331   WasFinished = true;
332   LangString(IDS_CHECKSUM_INFORMATION, pair.Title);
333   return S_OK;
334 }
335 
336 
337 
CalculateCrc2(const UString & methodName)338 HRESULT CApp::CalculateCrc2(const UString &methodName)
339 {
340   unsigned srcPanelIndex = GetFocusedPanelIndex();
341   CPanel &srcPanel = Panels[srcPanelIndex];
342 
343   CRecordVector<UInt32> indices;
344   srcPanel.Get_ItemIndices_OperSmart(indices);
345   if (indices.IsEmpty())
346     return S_OK;
347 
348   if (!srcPanel.Is_IO_FS_Folder())
349   {
350     CCopyToOptions options;
351     options.streamMode = true;
352     options.showErrorMessages = true;
353     options.hashMethods.Add(methodName);
354     options.NeedRegistryZone = false;
355 
356     UStringVector messages;
357     return srcPanel.CopyTo(options, indices, &messages);
358   }
359 
360   #ifdef Z7_EXTERNAL_CODECS
361 
362   LoadGlobalCodecs();
363 
364   #endif
365 
366   {
367     CThreadCrc t;
368 
369     {
370       UStringVector methods;
371       methods.Add(methodName);
372       RINOK(t.Hash.SetMethods(EXTERNAL_CODECS_VARS_G methods))
373     }
374 
375     FOR_VECTOR (i, indices)
376       t.Enumerator.FilePaths.Add(us2fs(srcPanel.GetItemRelPath(indices[i])));
377 
378     if (t.Enumerator.FilePaths.Size() == 1)
379       t.Hash.MainName = fs2us(t.Enumerator.FilePaths[0]);
380 
381     UString basePrefix = srcPanel.GetFsPath();
382     UString basePrefix2 = basePrefix;
383     if (basePrefix2.Back() == ':')
384     {
385       const int pos = basePrefix2.ReverseFind_PathSepar();
386       if (pos >= 0)
387         basePrefix2.DeleteFrom((unsigned)(pos + 1));
388     }
389 
390     t.Enumerator.BasePrefix = us2fs(basePrefix);
391     t.Enumerator.BasePrefix_for_Open = us2fs(basePrefix2);
392 
393     t.Enumerator.EnterToDirs = !GetFlatMode();
394 
395     t.ShowCompressionInfo = false;
396 
397     const UString title = LangString(IDS_CHECKSUM_CALCULATING);
398 
399     t.MainWindow = _window;
400     t.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE);
401     t.MainAddTitle = title;
402     t.MainAddTitle.Add_Space();
403 
404     RINOK(t.Create(title, _window))
405 
406     t.ShowFinalResults(_window);
407   }
408 
409   RefreshTitleAlways();
410   return S_OK;
411 }
412 
CalculateCrc(const char * methodName)413 void CApp::CalculateCrc(const char *methodName)
414 {
415   HRESULT res = CalculateCrc2(UString(methodName));
416   if (res != S_OK && res != E_ABORT)
417   {
418     unsigned srcPanelIndex = GetFocusedPanelIndex();
419     CPanel &srcPanel = Panels[srcPanelIndex];
420     srcPanel.MessageBox_Error_HRESULT(res);
421   }
422 }
423