1 // FileFolderPluginOpen.cpp 2 3 #include "StdAfx.h" 4 5 #include "resource.h" 6 7 #include "../../../Windows/FileName.h" 8 #include "../../../Windows/Thread.h" 9 10 #include "../Agent/Agent.h" 11 #include "../GUI/ExtractRes.h" 12 13 #include "FileFolderPluginOpen.h" 14 #include "FormatUtils.h" 15 #include "LangUtils.h" 16 #include "OpenCallback.h" 17 #include "PluginLoader.h" 18 #include "PropertyName.h" 19 #include "RegistryPlugins.h" 20 21 using namespace NWindows; 22 23 struct CThreadArchiveOpen 24 { 25 UString Path; 26 UString ArcFormat; 27 CMyComPtr<IInStream> InStream; 28 CMyComPtr<IFolderManager> FolderManager; 29 CMyComPtr<IProgress> OpenCallbackProgress; 30 31 COpenArchiveCallback *OpenCallbackSpec; 32 /* 33 CMyComPtr<IUnknown> 34 // CMyComPtr<IProgress> 35 // CMyComPtr<IArchiveOpenCallback> 36 OpenCallbackSpec_Ref; 37 */ 38 39 CMyComPtr<IFolderFolder> Folder; 40 HRESULT Result; 41 ProcessCThreadArchiveOpen42 void Process() 43 { 44 try 45 { 46 CProgressCloser closer(OpenCallbackSpec->ProgressDialog); 47 Result = FolderManager->OpenFolderFile(InStream, Path, ArcFormat, &Folder, OpenCallbackProgress); 48 } 49 catch(...) { Result = E_FAIL; } 50 } 51 MyThreadFunctionCThreadArchiveOpen52 static THREAD_FUNC_DECL MyThreadFunction(void *param) 53 { 54 ((CThreadArchiveOpen *)param)->Process(); 55 return 0; 56 } 57 }; 58 59 /* 60 static int FindPlugin(const CObjectVector<CPluginInfo> &plugins, const UString &pluginName) 61 { 62 for (int i = 0; i < plugins.Size(); i++) 63 if (plugins[i].Name.CompareNoCase(pluginName) == 0) 64 return i; 65 return -1; 66 } 67 */ 68 SplitNameToPureNameAndExtension(const FString & fullName,FString & pureName,FString & extensionDelimiter,FString & extension)69 static void SplitNameToPureNameAndExtension(const FString &fullName, 70 FString &pureName, FString &extensionDelimiter, FString &extension) 71 { 72 const int index = fullName.ReverseFind_Dot(); 73 if (index < 0) 74 { 75 pureName = fullName; 76 extensionDelimiter.Empty(); 77 extension.Empty(); 78 } 79 else 80 { 81 pureName.SetFrom(fullName, (unsigned)index); 82 extensionDelimiter = '.'; 83 extension = fullName.Ptr((unsigned)index + 1); 84 } 85 } 86 87 88 struct CArcLevelInfo 89 { 90 UString Error; 91 UString Path; 92 UString Type; 93 UString ErrorType; 94 UString ErrorFlags; 95 }; 96 97 98 struct CArcLevelsInfo 99 { 100 CObjectVector<CArcLevelInfo> Levels; // LastLevel Is NON-OPEN 101 }; 102 103 104 UString GetOpenArcErrorMessage(UInt32 errorFlags); 105 106 GetFolderLevels(CMyComPtr<IFolderFolder> & folder,CArcLevelsInfo & levels)107 static void GetFolderLevels(CMyComPtr<IFolderFolder> &folder, CArcLevelsInfo &levels) 108 { 109 levels.Levels.Clear(); 110 111 CMyComPtr<IGetFolderArcProps> getFolderArcProps; 112 folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); 113 114 if (!getFolderArcProps) 115 return; 116 CMyComPtr<IFolderArcProps> arcProps; 117 getFolderArcProps->GetFolderArcProps(&arcProps); 118 if (!arcProps) 119 return; 120 121 UInt32 numLevels; 122 if (arcProps->GetArcNumLevels(&numLevels) != S_OK) 123 numLevels = 0; 124 125 for (UInt32 level = 0; level <= numLevels; level++) 126 { 127 const PROPID propIDs[] = { kpidError, kpidPath, kpidType, kpidErrorType }; 128 129 CArcLevelInfo lev; 130 131 for (Int32 i = 0; i < 4; i++) 132 { 133 CMyComBSTR name; 134 NCOM::CPropVariant prop; 135 if (arcProps->GetArcProp(level, propIDs[i], &prop) != S_OK) 136 continue; 137 if (prop.vt != VT_EMPTY) 138 { 139 UString *s = NULL; 140 switch (propIDs[i]) 141 { 142 case kpidError: s = &lev.Error; break; 143 case kpidPath: s = &lev.Path; break; 144 case kpidType: s = &lev.Type; break; 145 case kpidErrorType: s = &lev.ErrorType; break; 146 } 147 *s = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?"; 148 } 149 } 150 151 { 152 NCOM::CPropVariant prop; 153 if (arcProps->GetArcProp(level, kpidErrorFlags, &prop) == S_OK) 154 { 155 UInt32 flags = GetOpenArcErrorFlags(prop); 156 if (flags != 0) 157 lev.ErrorFlags = GetOpenArcErrorMessage(flags); 158 } 159 } 160 161 levels.Levels.Add(lev); 162 } 163 } 164 GetBracedType(const wchar_t * type)165 static UString GetBracedType(const wchar_t *type) 166 { 167 UString s ('['); 168 s += type; 169 s.Add_Char(']'); 170 return s; 171 } 172 GetFolderError(CMyComPtr<IFolderFolder> & folder,UString & open_Errors,UString & nonOpen_Errors)173 static void GetFolderError(CMyComPtr<IFolderFolder> &folder, UString &open_Errors, UString &nonOpen_Errors) 174 { 175 CArcLevelsInfo levs; 176 GetFolderLevels(folder, levs); 177 open_Errors.Empty(); 178 nonOpen_Errors.Empty(); 179 180 FOR_VECTOR (i, levs.Levels) 181 { 182 bool isNonOpenLevel = (i == 0); 183 const CArcLevelInfo &lev = levs.Levels[levs.Levels.Size() - 1 - i]; 184 185 UString m; 186 187 if (!lev.ErrorType.IsEmpty()) 188 { 189 m = MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(lev.ErrorType)); 190 if (!isNonOpenLevel) 191 { 192 m.Add_LF(); 193 m += MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(lev.Type)); 194 } 195 } 196 197 if (!lev.Error.IsEmpty()) 198 { 199 if (!m.IsEmpty()) 200 m.Add_LF(); 201 m += GetBracedType(lev.Type); 202 m += " : "; 203 m += GetNameOfProperty(kpidError, L"Error"); 204 m += " : "; 205 m += lev.Error; 206 } 207 208 if (!lev.ErrorFlags.IsEmpty()) 209 { 210 if (!m.IsEmpty()) 211 m.Add_LF(); 212 m += GetNameOfProperty(kpidErrorFlags, L"Errors"); 213 m += ": "; 214 m += lev.ErrorFlags; 215 } 216 217 if (!m.IsEmpty()) 218 { 219 if (isNonOpenLevel) 220 { 221 UString &s = nonOpen_Errors; 222 s += lev.Path; 223 s.Add_LF(); 224 s += m; 225 } 226 else 227 { 228 UString &s = open_Errors; 229 if (!s.IsEmpty()) 230 s += "--------------------\n"; 231 s += lev.Path; 232 s.Add_LF(); 233 s += m; 234 } 235 } 236 } 237 } 238 239 #ifdef _MSC_VER 240 #pragma warning(error : 4702) // unreachable code 241 #endif 242 OpenFileFolderPlugin(IInStream * inStream,const FString & path,const UString & arcFormat,HWND parentWindow)243 HRESULT CFfpOpen::OpenFileFolderPlugin(IInStream *inStream, 244 const FString &path, const UString &arcFormat, HWND parentWindow) 245 { 246 /* 247 CObjectVector<CPluginInfo> plugins; 248 ReadFileFolderPluginInfoList(plugins); 249 */ 250 251 FString extension, name, pureName, dot; 252 253 const int slashPos = path.ReverseFind_PathSepar(); 254 FString dirPrefix; 255 FString fileName; 256 if (slashPos >= 0) 257 { 258 dirPrefix.SetFrom(path, (unsigned)(slashPos + 1)); 259 fileName = path.Ptr((unsigned)(slashPos + 1)); 260 } 261 else 262 fileName = path; 263 264 SplitNameToPureNameAndExtension(fileName, pureName, dot, extension); 265 266 /* 267 if (!extension.IsEmpty()) 268 { 269 CExtInfo extInfo; 270 if (ReadInternalAssociation(extension, extInfo)) 271 { 272 for (int i = extInfo.Plugins.Size() - 1; i >= 0; i--) 273 { 274 int pluginIndex = FindPlugin(plugins, extInfo.Plugins[i]); 275 if (pluginIndex >= 0) 276 { 277 const CPluginInfo plugin = plugins[pluginIndex]; 278 plugins.Delete(pluginIndex); 279 plugins.Insert(0, plugin); 280 } 281 } 282 } 283 } 284 */ 285 286 ErrorMessage.Empty(); 287 288 // FOR_VECTOR (i, plugins) 289 // { 290 /* 291 const CPluginInfo &plugin = plugins[i]; 292 if (!plugin.ClassID_Defined && !plugin.FilePath.IsEmpty()) 293 continue; 294 */ 295 CPluginLibrary library; 296 297 CThreadArchiveOpen t; 298 299 // if (plugin.FilePath.IsEmpty()) 300 t.FolderManager = new CArchiveFolderManager; 301 /* 302 else if (library.LoadAndCreateManager(plugin.FilePath, plugin.ClassID, &t.FolderManager) != S_OK) 303 continue; 304 */ 305 306 COpenArchiveCallback OpenCallbackSpec_loc; 307 t.OpenCallbackSpec = &OpenCallbackSpec_loc; 308 /* 309 t.OpenCallbackSpec = new COpenArchiveCallback; 310 t.OpenCallbackSpec_Ref = t.OpenCallbackSpec; 311 */ 312 t.OpenCallbackSpec->PasswordIsDefined = Encrypted; 313 t.OpenCallbackSpec->Password = Password; 314 t.OpenCallbackSpec->ParentWindow = parentWindow; 315 316 /* COpenCallbackImp object will exist after Open stage for multivolume archives */ 317 COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; 318 t.OpenCallbackProgress = openCallbackSpec; 319 // openCallbackSpec->Callback_Ref = t.OpenCallbackSpec; 320 // we set pointer without reference counter: 321 openCallbackSpec->Callback = 322 // openCallbackSpec->ReOpenCallback = 323 t.OpenCallbackSpec; 324 325 if (inStream) 326 openCallbackSpec->SetSubArchiveName(fs2us(fileName)); 327 else 328 { 329 RINOK(openCallbackSpec->Init2(dirPrefix, fileName)) 330 } 331 332 t.InStream = inStream; 333 t.Path = fs2us(path); 334 t.ArcFormat = arcFormat; 335 336 const UString progressTitle = LangString(IDS_OPENNING); 337 { 338 CProgressDialog &pd = t.OpenCallbackSpec->ProgressDialog; 339 pd.MainWindow = parentWindow; 340 pd.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); 341 pd.MainAddTitle = progressTitle + L' '; 342 pd.WaitMode = true; 343 } 344 345 { 346 NWindows::CThread thread; 347 const WRes wres = thread.Create(CThreadArchiveOpen::MyThreadFunction, &t); 348 if (wres != 0) 349 return HRESULT_FROM_WIN32(wres); 350 t.OpenCallbackSpec->StartProgressDialog(progressTitle, thread); 351 } 352 353 /* 354 if archive is multivolume: 355 COpenCallbackImp object will exist after Open stage. 356 COpenCallbackImp object will be deleted when last reference 357 from each volume object (CInFileStreamVol) will be closed (when archive will be closed). 358 */ 359 t.OpenCallbackProgress.Release(); 360 361 if (t.Result != S_FALSE && t.Result != S_OK) 362 return t.Result; 363 364 if (t.Folder) 365 { 366 UString open_Errors, nonOpen_Errors; 367 GetFolderError(t.Folder, open_Errors, nonOpen_Errors); 368 if (!nonOpen_Errors.IsEmpty()) 369 { 370 ErrorMessage = nonOpen_Errors; 371 // if (t.Result != S_OK) return t.Result; 372 /* if there are good open leves, and non0open level, 373 we could force error as critical error and return error here 374 but it's better to allow to open such rachives */ 375 // return S_FALSE; 376 } 377 } 378 379 // if (openCallbackSpec->PasswordWasAsked) 380 { 381 Encrypted = t.OpenCallbackSpec->PasswordIsDefined; 382 Password = t.OpenCallbackSpec->Password; 383 } 384 385 if (t.Result == S_OK) 386 { 387 Library.Attach(library.Detach()); 388 // Folder.Attach(t.Folder.Detach()); 389 Folder = t.Folder; 390 } 391 392 return t.Result; 393 // } 394 } 395