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