1 // ExtractCallbackSfx.h
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/Wildcard.h"
6 
7 #include "../../../Windows/FileDir.h"
8 #include "../../../Windows/FileFind.h"
9 #include "../../../Windows/FileName.h"
10 #include "../../../Windows/PropVariant.h"
11 
12 #include "ExtractCallbackSfx.h"
13 
14 using namespace NWindows;
15 using namespace NFile;
16 using namespace NDir;
17 
18 static LPCWSTR kCantDeleteFile = L"Can not delete output file";
19 static LPCWSTR kCantOpenFile = L"Can not open output file";
20 static LPCWSTR kUnsupportedMethod = L"Unsupported Method";
21 
Init(IInArchive * archiveHandler,const FString & directoryPath,const UString & itemDefaultName,const FILETIME & defaultMTime,UInt32 defaultAttributes)22 void CExtractCallbackImp::Init(IInArchive *archiveHandler,
23     const FString &directoryPath,
24     const UString &itemDefaultName,
25     const FILETIME &defaultMTime,
26     UInt32 defaultAttributes)
27 {
28   _message.Empty();
29   _isCorrupt = false;
30   _itemDefaultName = itemDefaultName;
31   _defaultMTime = defaultMTime;
32   _defaultAttributes = defaultAttributes;
33   _archiveHandler = archiveHandler;
34   _directoryPath = directoryPath;
35   NName::NormalizeDirPathPrefix(_directoryPath);
36 }
37 
Open_CheckBreak()38 HRESULT CExtractCallbackImp::Open_CheckBreak()
39 {
40   #ifndef _NO_PROGRESS
41   return ProgressDialog.Sync.ProcessStopAndPause();
42   #else
43   return S_OK;
44   #endif
45 }
46 
Open_SetTotal(const UInt64 *,const UInt64 *)47 HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
48 {
49   return S_OK;
50 }
51 
Open_SetCompleted(const UInt64 *,const UInt64 *)52 HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
53 {
54   #ifndef _NO_PROGRESS
55   return ProgressDialog.Sync.ProcessStopAndPause();
56   #else
57   return S_OK;
58   #endif
59 }
60 
Open_Finished()61 HRESULT CExtractCallbackImp::Open_Finished()
62 {
63   return S_OK;
64 }
65 
SetTotal(UInt64 size)66 STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 size)
67 {
68   #ifndef _NO_PROGRESS
69   ProgressDialog.Sync.SetProgress(size, 0);
70   #endif
71   return S_OK;
72 }
73 
SetCompleted(const UInt64 * completeValue)74 STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *completeValue)
75 {
76   #ifndef _NO_PROGRESS
77   RINOK(ProgressDialog.Sync.ProcessStopAndPause());
78   if (completeValue != NULL)
79     ProgressDialog.Sync.SetPos(*completeValue);
80   #endif
81   return S_OK;
82 }
83 
CreateComplexDirectory(const UStringVector & dirPathParts)84 void CExtractCallbackImp::CreateComplexDirectory(const UStringVector &dirPathParts)
85 {
86   FString fullPath = _directoryPath;
87   FOR_VECTOR (i, dirPathParts)
88   {
89     fullPath += us2fs(dirPathParts[i]);
90     CreateDir(fullPath);
91     fullPath.Add_PathSepar();
92   }
93 }
94 
GetStream(UInt32 index,ISequentialOutStream ** outStream,Int32 askExtractMode)95 STDMETHODIMP CExtractCallbackImp::GetStream(UInt32 index,
96     ISequentialOutStream **outStream, Int32 askExtractMode)
97 {
98   #ifndef _NO_PROGRESS
99   if (ProgressDialog.Sync.GetStopped())
100     return E_ABORT;
101   #endif
102   _outFileStream.Release();
103 
104   UString fullPath;
105   {
106     NCOM::CPropVariant prop;
107     RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop));
108     if (prop.vt == VT_EMPTY)
109       fullPath = _itemDefaultName;
110     else
111     {
112       if (prop.vt != VT_BSTR)
113         return E_FAIL;
114       fullPath.SetFromBstr(prop.bstrVal);
115     }
116     _filePath = fullPath;
117   }
118 
119   if (askExtractMode == NArchive::NExtract::NAskMode::kExtract)
120   {
121     NCOM::CPropVariant prop;
122     RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop));
123     if (prop.vt == VT_EMPTY)
124       _processedFileInfo.Attributes = _defaultAttributes;
125     else
126     {
127       if (prop.vt != VT_UI4)
128         return E_FAIL;
129       _processedFileInfo.Attributes = prop.ulVal;
130     }
131 
132     RINOK(_archiveHandler->GetProperty(index, kpidIsDir, &prop));
133     _processedFileInfo.IsDir = VARIANT_BOOLToBool(prop.boolVal);
134 
135     bool isAnti = false;
136     {
137       NCOM::CPropVariant propTemp;
138       RINOK(_archiveHandler->GetProperty(index, kpidIsAnti, &propTemp));
139       if (propTemp.vt == VT_BOOL)
140         isAnti = VARIANT_BOOLToBool(propTemp.boolVal);
141     }
142 
143     RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop));
144     switch (prop.vt)
145     {
146       case VT_EMPTY: _processedFileInfo.MTime = _defaultMTime; break;
147       case VT_FILETIME: _processedFileInfo.MTime = prop.filetime; break;
148       default: return E_FAIL;
149     }
150 
151     UStringVector pathParts;
152     SplitPathToParts(fullPath, pathParts);
153     if (pathParts.IsEmpty())
154       return E_FAIL;
155 
156     UString processedPath = fullPath;
157 
158     if (!_processedFileInfo.IsDir)
159       pathParts.DeleteBack();
160     if (!pathParts.IsEmpty())
161     {
162       if (!isAnti)
163         CreateComplexDirectory(pathParts);
164     }
165 
166     FString fullProcessedPath = _directoryPath + us2fs(processedPath);
167 
168     if (_processedFileInfo.IsDir)
169     {
170       _diskFilePath = fullProcessedPath;
171 
172       if (isAnti)
173         RemoveDir(_diskFilePath);
174       else
175         SetDirTime(_diskFilePath, NULL, NULL, &_processedFileInfo.MTime);
176       return S_OK;
177     }
178 
179     NFind::CFileInfo fileInfo;
180     if (fileInfo.Find(fullProcessedPath))
181     {
182       if (!DeleteFileAlways(fullProcessedPath))
183       {
184         _message = kCantDeleteFile;
185         return E_FAIL;
186       }
187     }
188 
189     if (!isAnti)
190     {
191       _outFileStreamSpec = new COutFileStream;
192       CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
193       if (!_outFileStreamSpec->Create(fullProcessedPath, true))
194       {
195         _message = kCantOpenFile;
196         return E_FAIL;
197       }
198       _outFileStream = outStreamLoc;
199       *outStream = outStreamLoc.Detach();
200     }
201     _diskFilePath = fullProcessedPath;
202   }
203   else
204   {
205     *outStream = NULL;
206   }
207   return S_OK;
208 }
209 
PrepareOperation(Int32 askExtractMode)210 STDMETHODIMP CExtractCallbackImp::PrepareOperation(Int32 askExtractMode)
211 {
212   _extractMode = (askExtractMode == NArchive::NExtract::NAskMode::kExtract);
213   return S_OK;
214 }
215 
SetOperationResult(Int32 resultEOperationResult)216 STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 resultEOperationResult)
217 {
218   switch (resultEOperationResult)
219   {
220     case NArchive::NExtract::NOperationResult::kOK:
221       break;
222 
223     default:
224     {
225       _outFileStream.Release();
226       switch (resultEOperationResult)
227       {
228         case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
229           _message = kUnsupportedMethod;
230           break;
231         default:
232           _isCorrupt = true;
233       }
234       return E_FAIL;
235     }
236   }
237   if (_outFileStream != NULL)
238   {
239     _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime);
240     RINOK(_outFileStreamSpec->Close());
241   }
242   _outFileStream.Release();
243   if (_extractMode)
244     SetFileAttrib(_diskFilePath, _processedFileInfo.Attributes);
245   return S_OK;
246 }
247