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 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 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 47 HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) 48 { 49 return S_OK; 50 } 51 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 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 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 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 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 202 STDMETHODIMP CExtractCallbackImp::PrepareOperation(Int32 askExtractMode) 203 { 204 _extractMode = (askExtractMode == NArchive::NExtract::NAskMode::kExtract); 205 return S_OK; 206 } 207 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