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