1 // ExtractCallback.h
2 
3 #ifndef __EXTRACT_CALLBACK_H
4 #define __EXTRACT_CALLBACK_H
5 
6 #include "../../../../C/Alloc.h"
7 
8 #include "../../../Common/MyCom.h"
9 #include "../../../Common/StringConvert.h"
10 
11 #ifndef _SFX
12 #include "../Agent/IFolderArchive.h"
13 #endif
14 
15 #include "../Common/ArchiveExtractCallback.h"
16 #include "../Common/ArchiveOpenCallback.h"
17 
18 #ifndef _NO_CRYPTO
19 #include "../../IPassword.h"
20 #endif
21 
22 #ifndef _SFX
23 #include "IFolder.h"
24 #endif
25 
26 #include "ProgressDialog2.h"
27 
28 #ifdef LANG
29 #include "LangUtils.h"
30 #endif
31 
32 #ifndef _SFX
33 
34 class CGrowBuf
35 {
36   Byte *_items;
37   size_t _size;
38 
39   CGrowBuf(const CGrowBuf &buffer);
40   void operator=(const CGrowBuf &buffer);
41 
42 public:
ReAlloc_KeepData(size_t newSize,size_t keepSize)43   bool ReAlloc_KeepData(size_t newSize, size_t keepSize)
44   {
45     void *buf = MyAlloc(newSize);
46     if (!buf)
47       return false;
48     memcpy(buf, _items, keepSize);
49     MyFree(_items);
50     _items = (Byte *)buf;
51     _size = newSize;
52     return true;
53   }
54 
CGrowBuf()55   CGrowBuf(): _items(0), _size(0) {}
~CGrowBuf()56   ~CGrowBuf() { MyFree(_items); }
57 
58   operator Byte *() { return _items; };
59   operator const Byte *() const { return _items; };
Size()60   size_t Size() const { return _size; }
61 };
62 
63 struct CVirtFile
64 {
65   CGrowBuf Data;
66 
67   UInt64 Size; // real size
68   UInt64 ExpectedSize; // the size from props request. 0 if unknown
69 
70   UString Name;
71 
72   bool CTimeDefined;
73   bool ATimeDefined;
74   bool MTimeDefined;
75   bool AttribDefined;
76 
77   bool IsDir;
78   bool IsAltStream;
79 
80   DWORD Attrib;
81 
82   FILETIME CTime;
83   FILETIME ATime;
84   FILETIME MTime;
85 
CVirtFileCVirtFile86   CVirtFile():
87     CTimeDefined(false),
88     ATimeDefined(false),
89     MTimeDefined(false),
90     AttribDefined(false),
91     IsDir(false),
92     IsAltStream(false) {}
93 };
94 
95 class CVirtFileSystem:
96   public ISequentialOutStream,
97   public CMyUnknownImp
98 {
99   UInt64 _totalAllocSize;
100 
101   size_t _pos;
102   unsigned _numFlushed;
103   bool _fileIsOpen;
104   bool _fileMode;
105   COutFileStream *_outFileStreamSpec;
106   CMyComPtr<ISequentialOutStream> _outFileStream;
107 public:
108   CObjectVector<CVirtFile> Files;
109   UInt64 MaxTotalAllocSize;
110   FString DirPrefix;
111 
AddNewFile()112   CVirtFile &AddNewFile()
113   {
114     if (!Files.IsEmpty())
115     {
116       MaxTotalAllocSize -= Files.Back().Data.Size();
117     }
118     return Files.AddNew();
119   }
CloseMemFile()120   HRESULT CloseMemFile()
121   {
122     if (_fileMode)
123     {
124       return FlushToDisk(true);
125     }
126     CVirtFile &file = Files.Back();
127     if (file.Data.Size() != file.Size)
128     {
129       file.Data.ReAlloc_KeepData((size_t)file.Size, (size_t)file.Size);
130     }
131     return S_OK;
132   }
133 
IsStreamInMem()134   bool IsStreamInMem() const
135   {
136     if (_fileMode)
137       return false;
138     if (Files.Size() < 1 || Files[0].IsAltStream || Files[0].IsDir)
139       return false;
140     return true;
141   }
GetMemStreamWrittenSize()142   size_t GetMemStreamWrittenSize() const { return _pos; }
143 
CVirtFileSystem()144   CVirtFileSystem(): _outFileStreamSpec(NULL), MaxTotalAllocSize((UInt64)0 - 1) {}
145 
Init()146   void Init()
147   {
148     _totalAllocSize = 0;
149     _fileMode = false;
150     _pos = 0;
151     _numFlushed = 0;
152     _fileIsOpen = false;
153   }
154 
155   HRESULT CloseFile(const FString &path);
156   HRESULT FlushToDisk(bool closeLast);
GetPos()157   size_t GetPos() const { return _pos; }
158 
159   MY_UNKNOWN_IMP
160   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
161 };
162 
163 #endif
164 
165 class CExtractCallbackImp:
166   public IExtractCallbackUI, // it includes IFolderArchiveExtractCallback
167   public IOpenCallbackUI,
168   #ifndef _SFX
169   public IFolderOperationsExtractCallback,
170   public IFolderExtractToStreamCallback,
171   public ICompressProgressInfo,
172   #endif
173   #ifndef _NO_CRYPTO
174   public ICryptoGetTextPassword,
175   #endif
176   public CMyUnknownImp
177 {
178   HRESULT MessageError(const char *message, const FString &path);
179 public:
180   MY_QUERYINTERFACE_BEGIN2(IFolderArchiveExtractCallback)
181   #ifndef _SFX
182   MY_QUERYINTERFACE_ENTRY(IFolderOperationsExtractCallback)
183   MY_QUERYINTERFACE_ENTRY(IFolderExtractToStreamCallback)
184   MY_QUERYINTERFACE_ENTRY(ICompressProgressInfo)
185   #endif
186   #ifndef _NO_CRYPTO
187   MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
188   #endif
189   MY_QUERYINTERFACE_END
190   MY_ADDREF_RELEASE
191 
192   INTERFACE_IProgress(;)
193   INTERFACE_IOpenCallbackUI(;)
194 
195   // IFolderArchiveExtractCallback
196   // STDMETHOD(SetTotalFiles)(UInt64 total);
197   // STDMETHOD(SetCompletedFiles)(const UInt64 *value);
198   STDMETHOD(AskOverwrite)(
199       const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
200       const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
201       Int32 *answer);
202   STDMETHOD (PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position);
203 
204   STDMETHOD(MessageError)(const wchar_t *message);
205   STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted);
206 
207   // IExtractCallbackUI
208 
209   HRESULT BeforeOpen(const wchar_t *name);
210   HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted);
211   HRESULT SetError(int level, const wchar_t *name,
212       UInt32 errorFlags, const wchar_t *errors,
213       UInt32 warningFlags, const wchar_t *warnings);
214   HRESULT ThereAreNoFiles();
215   HRESULT ExtractResult(HRESULT result);
216   HRESULT OpenTypeWarning(const wchar_t *name, const wchar_t *okType, const wchar_t *errorType);
217 
218   #ifndef _NO_CRYPTO
219   HRESULT SetPassword(const UString &password);
220   #endif
221 
222   #ifndef _SFX
223   // IFolderOperationsExtractCallback
224   STDMETHOD(AskWrite)(
225       const wchar_t *srcPath,
226       Int32 srcIsFolder,
227       const FILETIME *srcTime,
228       const UInt64 *srcSize,
229       const wchar_t *destPathRequest,
230       BSTR *destPathResult,
231       Int32 *writeAnswer);
232   STDMETHOD(ShowMessage)(const wchar_t *message);
233   STDMETHOD(SetCurrentFilePath)(const wchar_t *filePath);
234   STDMETHOD(SetNumFiles)(UInt64 numFiles);
235   INTERFACE_IFolderExtractToStreamCallback(;)
236   STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
237   #endif
238 
239   // ICryptoGetTextPassword
240   #ifndef _NO_CRYPTO
241   STDMETHOD(CryptoGetTextPassword)(BSTR *password);
242   #endif
243 
244 private:
245   UString _currentArchivePath;
246   bool _needWriteArchivePath;
247 
248   UString _currentFilePath;
249   bool _isFolder;
250 
251   bool _isAltStream;
252   UInt64 _curSize;
253   bool _curSizeDefined;
254   UString _filePath;
255   // bool _extractMode;
256   // bool _testMode;
257   bool _newVirtFileWasAdded;
258   bool _needUpdateStat;
259 
260 
261   HRESULT SetCurrentFilePath2(const wchar_t *filePath);
262   void AddError_Message(LPCWSTR message);
263 
264   #ifndef _SFX
265   bool _hashStreamWasUsed;
266   COutStreamWithHash *_hashStreamSpec;
267   CMyComPtr<ISequentialOutStream> _hashStream;
268   IHashCalc *_hashCalc; // it's for stat in Test operation
269   #endif
270 
271 public:
272 
273   #ifndef _SFX
274   CVirtFileSystem *VirtFileSystemSpec;
275   CMyComPtr<ISequentialOutStream> VirtFileSystem;
276   #endif
277 
278   bool ProcessAltStreams;
279 
280   bool StreamMode;
281 
282   CProgressDialog *ProgressDialog;
283   #ifndef _SFX
284   UInt64 NumFolders;
285   UInt64 NumFiles;
286   bool NeedAddFile;
287   #endif
288   UInt32 NumArchiveErrors;
289   bool ThereAreMessageErrors;
290   NExtract::NOverwriteMode::EEnum OverwriteMode;
291 
292   #ifndef _NO_CRYPTO
293   bool PasswordIsDefined;
294   bool PasswordWasAsked;
295   UString Password;
296   #endif
297 
CExtractCallbackImp()298   CExtractCallbackImp():
299     #ifndef _NO_CRYPTO
300     PasswordIsDefined(false),
301     PasswordWasAsked(false),
302     #endif
303     OverwriteMode(NExtract::NOverwriteMode::kAsk),
304     StreamMode(false),
305     ProcessAltStreams(true)
306     #ifndef _SFX
307     , _hashCalc(NULL)
308     #endif
309     {}
310 
311   ~CExtractCallbackImp();
312   void Init();
313 
314   #ifndef _SFX
SetHashCalc(IHashCalc * hashCalc)315   void SetHashCalc(IHashCalc *hashCalc) { _hashCalc = hashCalc; }
316 
SetHashMethods(IHashCalc * hash)317   void SetHashMethods(IHashCalc *hash)
318   {
319     if (!hash)
320       return;
321     _hashStreamSpec = new COutStreamWithHash;
322     _hashStream = _hashStreamSpec;
323     _hashStreamSpec->_hash = hash;
324   }
325   #endif
326 
IsOK()327   bool IsOK() const { return NumArchiveErrors == 0 && !ThereAreMessageErrors; }
328 };
329 
330 #endif
331