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 LPCSTR const kCantDeleteFile = "Can not delete output file";
19 static LPCSTR const kCantOpenFile = "Can not open output file";
20 static LPCSTR const kUnsupportedMethod = "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