1 // ExtractCallback.h
2
3 #include "StdAfx.h"
4
5 #include "ExtractCallback.h"
6
7 #include "Common/Wildcard.h"
8 #include "Common/StringConvert.h"
9
10 #include "Windows/COM.h"
11 #include "Windows/FileDir.h"
12 #include "Windows/FileFind.h"
13 #include "Windows/Time.h"
14 #include "Windows/Defs.h"
15 #include "Windows/PropVariant.h"
16
17 #include "Windows/PropVariantConversions.h"
18
19 using namespace NWindows;
20 using namespace NFile;
21
22 static LPCWSTR kErrorTitle = L"7-Zip";
23 static LPCWSTR kCantDeleteFile = L"Can not delete output file";
24 static LPCWSTR kCantOpenFile = L"Can not open output file";
25 static LPCWSTR kUnsupportedMethod = L"Unsupported Method";
26 // static LPCWSTR kCRCFailed = L"CRC Failed";
27 // static LPCWSTR kDataError = L"Data Error";
28 // static LPCWSTR kUnknownError = L""Unknown Error";
29
Init(IInArchive * archiveHandler,const UString & directoryPath,const UString & itemDefaultName,const FILETIME & utcLastWriteTimeDefault,UInt32 attributesDefault)30 void CExtractCallbackImp::Init(IInArchive *archiveHandler,
31 const UString &directoryPath,
32 const UString &itemDefaultName,
33 const FILETIME &utcLastWriteTimeDefault,
34 UInt32 attributesDefault)
35 {
36 _message.Empty();
37 _isCorrupt = false;
38 _itemDefaultName = itemDefaultName;
39 _utcLastWriteTimeDefault = utcLastWriteTimeDefault;
40 _attributesDefault = attributesDefault;
41 _archiveHandler = archiveHandler;
42 _directoryPath = directoryPath;
43 NName::NormalizeDirPathPrefix(_directoryPath);
44 }
45
SetTotal(UInt64 size)46 STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 size)
47 {
48 #ifndef _NO_PROGRESS
49 ProgressDialog.ProgressSynch.SetProgress(size, 0);
50 #endif
51 return S_OK;
52 }
53
SetCompleted(const UInt64 * completeValue)54 STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *completeValue)
55 {
56 #ifndef _NO_PROGRESS
57 while(true)
58 {
59 if(ProgressDialog.ProgressSynch.GetStopped())
60 return E_ABORT;
61 if(!ProgressDialog.ProgressSynch.GetPaused())
62 break;
63 ::Sleep(100);
64 }
65 if (completeValue != NULL)
66 ProgressDialog.ProgressSynch.SetPos(*completeValue);
67 #endif
68 return S_OK;
69 }
70
CreateComplexDirectory(const UStringVector & dirPathParts)71 void CExtractCallbackImp::CreateComplexDirectory(const UStringVector &dirPathParts)
72 {
73 UString fullPath = _directoryPath;
74 for(int i = 0; i < dirPathParts.Size(); i++)
75 {
76 fullPath += dirPathParts[i];
77 NDirectory::MyCreateDirectory(fullPath);
78 fullPath += NName::kDirDelimiter;
79 }
80 }
81
GetStream(UInt32 index,ISequentialOutStream ** outStream,Int32 askExtractMode)82 STDMETHODIMP CExtractCallbackImp::GetStream(UInt32 index,
83 ISequentialOutStream **outStream, Int32 askExtractMode)
84 {
85 #ifndef _NO_PROGRESS
86 if(ProgressDialog.ProgressSynch.GetStopped())
87 return E_ABORT;
88 #endif
89 _outFileStream.Release();
90 NCOM::CPropVariant propVariantName;
91 RINOK(_archiveHandler->GetProperty(index, kpidPath, &propVariantName));
92 UString fullPath;
93 if(propVariantName.vt == VT_EMPTY)
94 fullPath = _itemDefaultName;
95 else
96 {
97 if(propVariantName.vt != VT_BSTR)
98 return E_FAIL;
99 fullPath = propVariantName.bstrVal;
100 }
101 _filePath = fullPath;
102
103 // m_CurrentFilePath = GetSystemString(fullPath, _codePage);
104
105 if(askExtractMode == NArchive::NExtract::NAskMode::kExtract)
106 {
107 NCOM::CPropVariant propVariant;
108 RINOK(_archiveHandler->GetProperty(index, kpidAttributes, &propVariant));
109 if (propVariant.vt == VT_EMPTY)
110 _processedFileInfo.Attributes = _attributesDefault;
111 else
112 {
113 if (propVariant.vt != VT_UI4)
114 return E_FAIL;
115 _processedFileInfo.Attributes = propVariant.ulVal;
116 }
117
118 RINOK(_archiveHandler->GetProperty(index, kpidIsFolder, &propVariant));
119 _processedFileInfo.IsDirectory = VARIANT_BOOLToBool(propVariant.boolVal);
120
121 bool isAnti = false;
122 {
123 NCOM::CPropVariant propVariantTemp;
124 RINOK(_archiveHandler->GetProperty(index, kpidIsAnti,
125 &propVariantTemp));
126 if (propVariantTemp.vt == VT_BOOL)
127 isAnti = VARIANT_BOOLToBool(propVariantTemp.boolVal);
128 }
129
130 RINOK(_archiveHandler->GetProperty(index, kpidLastWriteTime, &propVariant));
131 switch(propVariant.vt)
132 {
133 case VT_EMPTY:
134 _processedFileInfo.UTCLastWriteTime = _utcLastWriteTimeDefault;
135 break;
136 case VT_FILETIME:
137 _processedFileInfo.UTCLastWriteTime = propVariant.filetime;
138 break;
139 default:
140 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.IsDirectory)
151 pathParts.DeleteBack();
152 if (!pathParts.IsEmpty())
153 {
154 if (!isAnti)
155 CreateComplexDirectory(pathParts);
156 }
157
158 UString fullProcessedPath = _directoryPath + processedPath;
159
160 if(_processedFileInfo.IsDirectory)
161 {
162 _diskFilePath = fullProcessedPath;
163
164 if (isAnti)
165 NDirectory::MyRemoveDirectory(_diskFilePath);
166 return S_OK;
167 }
168
169 NFind::CFileInfoW fileInfo;
170 if(NFind::FindFile(fullProcessedPath, fileInfo))
171 {
172 if (!NDirectory::DeleteFileAlways(fullProcessedPath))
173 {
174 _message = kCantDeleteFile;
175 return E_FAIL;
176 }
177 }
178
179 if (!isAnti)
180 {
181 _outFileStreamSpec = new COutFileStream;
182 CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
183 if (!_outFileStreamSpec->Create(fullProcessedPath, true))
184 {
185 _message = kCantOpenFile;
186 return E_FAIL;
187 }
188 _outFileStream = outStreamLoc;
189 *outStream = outStreamLoc.Detach();
190 }
191 _diskFilePath = fullProcessedPath;
192 }
193 else
194 {
195 *outStream = NULL;
196 }
197 return S_OK;
198 }
199
PrepareOperation(Int32 askExtractMode)200 STDMETHODIMP CExtractCallbackImp::PrepareOperation(Int32 askExtractMode)
201 {
202 _extractMode = false;
203 switch (askExtractMode)
204 {
205 case NArchive::NExtract::NAskMode::kExtract:
206 _extractMode = true;
207 break;
208 }
209 return S_OK;
210 }
211
SetOperationResult(Int32 resultEOperationResult)212 STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 resultEOperationResult)
213 {
214 switch(resultEOperationResult)
215 {
216 case NArchive::NExtract::NOperationResult::kOK:
217 {
218 break;
219 }
220 default:
221 {
222 _outFileStream.Release();
223 switch(resultEOperationResult)
224 {
225 case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
226 _message = kUnsupportedMethod;
227 break;
228 case NArchive::NExtract::NOperationResult::kCRCError:
229 _isCorrupt = true;
230 // _message = kCRCFailed;
231 break;
232 case NArchive::NExtract::NOperationResult::kDataError:
233 _isCorrupt = true;
234 // _message = kDataError;
235 break;
236 default:
237 _isCorrupt = true;
238 }
239 return E_FAIL;
240 }
241 }
242 if(_outFileStream != NULL)
243 _outFileStreamSpec->File.SetLastWriteTime(&_processedFileInfo.UTCLastWriteTime);
244 _outFileStream.Release();
245 if (_extractMode)
246 NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attributes);
247 return S_OK;
248 }
249
250