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
SetTotal(UInt64 size)61 STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 size)
62 {
63 #ifndef _NO_PROGRESS
64 ProgressDialog.Sync.SetProgress(size, 0);
65 #endif
66 return S_OK;
67 }
68
SetCompleted(const UInt64 * completeValue)69 STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *completeValue)
70 {
71 #ifndef _NO_PROGRESS
72 RINOK(ProgressDialog.Sync.ProcessStopAndPause());
73 if (completeValue != NULL)
74 ProgressDialog.Sync.SetPos(*completeValue);
75 #endif
76 return S_OK;
77 }
78
CreateComplexDirectory(const UStringVector & dirPathParts)79 void CExtractCallbackImp::CreateComplexDirectory(const UStringVector &dirPathParts)
80 {
81 FString fullPath = _directoryPath;
82 FOR_VECTOR (i, dirPathParts)
83 {
84 fullPath += us2fs(dirPathParts[i]);
85 CreateDir(fullPath);
86 fullPath += FCHAR_PATH_SEPARATOR;
87 }
88 }
89
GetStream(UInt32 index,ISequentialOutStream ** outStream,Int32 askExtractMode)90 STDMETHODIMP CExtractCallbackImp::GetStream(UInt32 index,
91 ISequentialOutStream **outStream, Int32 askExtractMode)
92 {
93 #ifndef _NO_PROGRESS
94 if (ProgressDialog.Sync.GetStopped())
95 return E_ABORT;
96 #endif
97 _outFileStream.Release();
98 NCOM::CPropVariant propVariantName;
99 RINOK(_archiveHandler->GetProperty(index, kpidPath, &propVariantName));
100 UString fullPath;
101 if (propVariantName.vt == VT_EMPTY)
102 fullPath = _itemDefaultName;
103 else
104 {
105 if (propVariantName.vt != VT_BSTR)
106 return E_FAIL;
107 fullPath = propVariantName.bstrVal;
108 }
109 _filePath = fullPath;
110
111 if (askExtractMode == NArchive::NExtract::NAskMode::kExtract)
112 {
113 NCOM::CPropVariant prop;
114 RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop));
115 if (prop.vt == VT_EMPTY)
116 _processedFileInfo.Attributes = _defaultAttributes;
117 else
118 {
119 if (prop.vt != VT_UI4)
120 return E_FAIL;
121 _processedFileInfo.Attributes = prop.ulVal;
122 }
123
124 RINOK(_archiveHandler->GetProperty(index, kpidIsDir, &prop));
125 _processedFileInfo.IsDir = VARIANT_BOOLToBool(prop.boolVal);
126
127 bool isAnti = false;
128 {
129 NCOM::CPropVariant propTemp;
130 RINOK(_archiveHandler->GetProperty(index, kpidIsAnti, &propTemp));
131 if (propTemp.vt == VT_BOOL)
132 isAnti = VARIANT_BOOLToBool(propTemp.boolVal);
133 }
134
135 RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop));
136 switch(prop.vt)
137 {
138 case VT_EMPTY: _processedFileInfo.MTime = _defaultMTime; break;
139 case VT_FILETIME: _processedFileInfo.MTime = prop.filetime; break;
140 default: return E_FAIL;
141 }
142
143 UStringVector pathParts;
144 SplitPathToParts(fullPath, pathParts);
145 if (pathParts.IsEmpty())
146 return E_FAIL;
147
148 UString processedPath = fullPath;
149
150 if (!_processedFileInfo.IsDir)
151 pathParts.DeleteBack();
152 if (!pathParts.IsEmpty())
153 {
154 if (!isAnti)
155 CreateComplexDirectory(pathParts);
156 }
157
158 FString fullProcessedPath = _directoryPath + us2fs(processedPath);
159
160 if (_processedFileInfo.IsDir)
161 {
162 _diskFilePath = fullProcessedPath;
163
164 if (isAnti)
165 RemoveDir(_diskFilePath);
166 else
167 SetDirTime(_diskFilePath, NULL, NULL, &_processedFileInfo.MTime);
168 return S_OK;
169 }
170
171 NFind::CFileInfo fileInfo;
172 if (fileInfo.Find(fullProcessedPath))
173 {
174 if (!DeleteFileAlways(fullProcessedPath))
175 {
176 _message = kCantDeleteFile;
177 return E_FAIL;
178 }
179 }
180
181 if (!isAnti)
182 {
183 _outFileStreamSpec = new COutFileStream;
184 CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
185 if (!_outFileStreamSpec->Create(fullProcessedPath, true))
186 {
187 _message = kCantOpenFile;
188 return E_FAIL;
189 }
190 _outFileStream = outStreamLoc;
191 *outStream = outStreamLoc.Detach();
192 }
193 _diskFilePath = fullProcessedPath;
194 }
195 else
196 {
197 *outStream = NULL;
198 }
199 return S_OK;
200 }
201
PrepareOperation(Int32 askExtractMode)202 STDMETHODIMP CExtractCallbackImp::PrepareOperation(Int32 askExtractMode)
203 {
204 _extractMode = (askExtractMode == NArchive::NExtract::NAskMode::kExtract);
205 return S_OK;
206 }
207
SetOperationResult(Int32 resultEOperationResult)208 STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 resultEOperationResult)
209 {
210 switch(resultEOperationResult)
211 {
212 case NArchive::NExtract::NOperationResult::kOK:
213 break;
214
215 default:
216 {
217 _outFileStream.Release();
218 switch(resultEOperationResult)
219 {
220 case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
221 _message = kUnsupportedMethod;
222 break;
223 default:
224 _isCorrupt = true;
225 }
226 return E_FAIL;
227 }
228 }
229 if (_outFileStream != NULL)
230 {
231 _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime);
232 RINOK(_outFileStreamSpec->Close());
233 }
234 _outFileStream.Release();
235 if (_extractMode)
236 SetFileAttrib(_diskFilePath, _processedFileInfo.Attributes);
237 return S_OK;
238 }
239