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> OpenCallback;
30 COpenArchiveCallback *OpenCallbackSpec;
31
32 CMyComPtr<IFolderFolder> Folder;
33 HRESULT Result;
34
ProcessCThreadArchiveOpen35 void Process()
36 {
37 try
38 {
39 CProgressCloser closer(OpenCallbackSpec->ProgressDialog);
40 Result = FolderManager->OpenFolderFile(InStream, Path, ArcFormat, &Folder, OpenCallback);
41 }
42 catch(...) { Result = E_FAIL; }
43 }
44
MyThreadFunctionCThreadArchiveOpen45 static THREAD_FUNC_DECL MyThreadFunction(void *param)
46 {
47 ((CThreadArchiveOpen *)param)->Process();
48 return 0;
49 }
50 };
51
52 /*
53 static int FindPlugin(const CObjectVector<CPluginInfo> &plugins, const UString &pluginName)
54 {
55 for (int i = 0; i < plugins.Size(); i++)
56 if (plugins[i].Name.CompareNoCase(pluginName) == 0)
57 return i;
58 return -1;
59 }
60 */
61
SplitNameToPureNameAndExtension(const FString & fullName,FString & pureName,FString & extensionDelimiter,FString & extension)62 static void SplitNameToPureNameAndExtension(const FString &fullName,
63 FString &pureName, FString &extensionDelimiter, FString &extension)
64 {
65 int index = fullName.ReverseFind_Dot();
66 if (index < 0)
67 {
68 pureName = fullName;
69 extensionDelimiter.Empty();
70 extension.Empty();
71 }
72 else
73 {
74 pureName.SetFrom(fullName, index);
75 extensionDelimiter = '.';
76 extension = fullName.Ptr((unsigned)index + 1);
77 }
78 }
79
80
81 struct CArcLevelInfo
82 {
83 UString Error;
84 UString Path;
85 UString Type;
86 UString ErrorType;
87 UString ErrorFlags;
88 };
89
90
91 struct CArcLevelsInfo
92 {
93 CObjectVector<CArcLevelInfo> Levels; // LastLevel Is NON-OPEN
94 };
95
96
97 UString GetOpenArcErrorMessage(UInt32 errorFlags);
98
99
GetFolderLevels(CMyComPtr<IFolderFolder> & folder,CArcLevelsInfo & levels)100 static void GetFolderLevels(CMyComPtr<IFolderFolder> &folder, CArcLevelsInfo &levels)
101 {
102 levels.Levels.Clear();
103
104 CMyComPtr<IGetFolderArcProps> getFolderArcProps;
105 folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
106
107 if (!getFolderArcProps)
108 return;
109 CMyComPtr<IFolderArcProps> arcProps;
110 getFolderArcProps->GetFolderArcProps(&arcProps);
111 if (!arcProps)
112 return;
113
114 UInt32 numLevels;
115 if (arcProps->GetArcNumLevels(&numLevels) != S_OK)
116 numLevels = 0;
117
118 for (UInt32 level = 0; level <= numLevels; level++)
119 {
120 const PROPID propIDs[] = { kpidError, kpidPath, kpidType, kpidErrorType };
121
122 CArcLevelInfo lev;
123
124 for (Int32 i = 0; i < 4; i++)
125 {
126 CMyComBSTR name;
127 NCOM::CPropVariant prop;
128 if (arcProps->GetArcProp(level, propIDs[i], &prop) != S_OK)
129 continue;
130 if (prop.vt != VT_EMPTY)
131 {
132 UString *s = NULL;
133 switch (propIDs[i])
134 {
135 case kpidError: s = &lev.Error; break;
136 case kpidPath: s = &lev.Path; break;
137 case kpidType: s = &lev.Type; break;
138 case kpidErrorType: s = &lev.ErrorType; break;
139 }
140 *s = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?";
141 }
142 }
143
144 {
145 NCOM::CPropVariant prop;
146 if (arcProps->GetArcProp(level, kpidErrorFlags, &prop) == S_OK)
147 {
148 UInt32 flags = GetOpenArcErrorFlags(prop);
149 if (flags != 0)
150 lev.ErrorFlags = GetOpenArcErrorMessage(flags);
151 }
152 }
153
154 levels.Levels.Add(lev);
155 }
156 }
157
GetBracedType(const wchar_t * type)158 static UString GetBracedType(const wchar_t *type)
159 {
160 UString s ('[');
161 s += type;
162 s += ']';
163 return s;
164 }
165
GetFolderError(CMyComPtr<IFolderFolder> & folder,UString & open_Errors,UString & nonOpen_Errors)166 static void GetFolderError(CMyComPtr<IFolderFolder> &folder, UString &open_Errors, UString &nonOpen_Errors)
167 {
168 CArcLevelsInfo levs;
169 GetFolderLevels(folder, levs);
170 open_Errors.Empty();
171 nonOpen_Errors.Empty();
172
173 FOR_VECTOR (i, levs.Levels)
174 {
175 bool isNonOpenLevel = (i == 0);
176 const CArcLevelInfo &lev = levs.Levels[levs.Levels.Size() - 1 - i];
177
178 UString m;
179
180 if (!lev.ErrorType.IsEmpty())
181 {
182 m = MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(lev.ErrorType));
183 if (!isNonOpenLevel)
184 {
185 m.Add_LF();
186 m += MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(lev.Type));
187 }
188 }
189
190 if (!lev.Error.IsEmpty())
191 {
192 if (!m.IsEmpty())
193 m.Add_LF();
194 m += GetBracedType(lev.Type);
195 m += " : ";
196 m += GetNameOfProperty(kpidError, L"Error");
197 m += " : ";
198 m += lev.Error;
199 }
200
201 if (!lev.ErrorFlags.IsEmpty())
202 {
203 if (!m.IsEmpty())
204 m.Add_LF();
205 m += GetNameOfProperty(kpidErrorFlags, L"Errors");
206 m += ": ";
207 m += lev.ErrorFlags;
208 }
209
210 if (!m.IsEmpty())
211 {
212 if (isNonOpenLevel)
213 {
214 UString &s = nonOpen_Errors;
215 s += lev.Path;
216 s.Add_LF();
217 s += m;
218 }
219 else
220 {
221 UString &s = open_Errors;
222 if (!s.IsEmpty())
223 s += "--------------------\n";
224 s += lev.Path;
225 s.Add_LF();
226 s += m;
227 }
228 }
229 }
230 }
231
232
OpenFileFolderPlugin(IInStream * inStream,const FString & path,const UString & arcFormat,HWND parentWindow)233 HRESULT CFfpOpen::OpenFileFolderPlugin(IInStream *inStream,
234 const FString &path, const UString &arcFormat, HWND parentWindow)
235 {
236 CObjectVector<CPluginInfo> plugins;
237 ReadFileFolderPluginInfoList(plugins);
238
239 FString extension, name, pureName, dot;
240
241 int slashPos = path.ReverseFind_PathSepar();
242 FString dirPrefix;
243 FString fileName;
244 if (slashPos >= 0)
245 {
246 dirPrefix.SetFrom(path, (unsigned)(slashPos + 1));
247 fileName = path.Ptr((unsigned)(slashPos + 1));
248 }
249 else
250 fileName = path;
251
252 SplitNameToPureNameAndExtension(fileName, pureName, dot, extension);
253
254 /*
255 if (!extension.IsEmpty())
256 {
257 CExtInfo extInfo;
258 if (ReadInternalAssociation(extension, extInfo))
259 {
260 for (int i = extInfo.Plugins.Size() - 1; i >= 0; i--)
261 {
262 int pluginIndex = FindPlugin(plugins, extInfo.Plugins[i]);
263 if (pluginIndex >= 0)
264 {
265 const CPluginInfo plugin = plugins[pluginIndex];
266 plugins.Delete(pluginIndex);
267 plugins.Insert(0, plugin);
268 }
269 }
270 }
271 }
272 */
273
274 ErrorMessage.Empty();
275
276 FOR_VECTOR (i, plugins)
277 {
278 const CPluginInfo &plugin = plugins[i];
279 if (!plugin.ClassIDDefined)
280 continue;
281 CPluginLibrary library;
282
283 CThreadArchiveOpen t;
284
285 if (plugin.FilePath.IsEmpty())
286 t.FolderManager = new CArchiveFolderManager;
287 else if (library.LoadAndCreateManager(plugin.FilePath, plugin.ClassID, &t.FolderManager) != S_OK)
288 continue;
289
290 t.OpenCallbackSpec = new COpenArchiveCallback;
291 t.OpenCallback = t.OpenCallbackSpec;
292 t.OpenCallbackSpec->PasswordIsDefined = Encrypted;
293 t.OpenCallbackSpec->Password = Password;
294 t.OpenCallbackSpec->ParentWindow = parentWindow;
295
296 if (inStream)
297 t.OpenCallbackSpec->SetSubArchiveName(fs2us(fileName));
298 else
299 {
300 RINOK(t.OpenCallbackSpec->LoadFileInfo2(dirPrefix, fileName));
301 }
302
303 t.InStream = inStream;
304 t.Path = fs2us(path);
305 t.ArcFormat = arcFormat;
306
307 const UString progressTitle = LangString(IDS_OPENNING);
308 {
309 CProgressDialog &pd = t.OpenCallbackSpec->ProgressDialog;
310 pd.MainWindow = parentWindow;
311 pd.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE);
312 pd.MainAddTitle = progressTitle + L' ';
313 pd.WaitMode = true;
314 }
315
316 {
317 NWindows::CThread thread;
318 RINOK(thread.Create(CThreadArchiveOpen::MyThreadFunction, &t));
319 t.OpenCallbackSpec->StartProgressDialog(progressTitle, thread);
320 }
321
322 if (t.Result != S_FALSE && t.Result != S_OK)
323 return t.Result;
324
325 if (t.Folder)
326 {
327 UString open_Errors, nonOpen_Errors;
328 GetFolderError(t.Folder, open_Errors, nonOpen_Errors);
329 if (!nonOpen_Errors.IsEmpty())
330 {
331 ErrorMessage = nonOpen_Errors;
332 // if (t.Result != S_OK) return t.Result;
333 /* if there are good open leves, and non0open level,
334 we could force error as critical error and return error here
335 but it's better to allow to open such rachives */
336 // return S_FALSE;
337 }
338 }
339
340 // if (openCallbackSpec->PasswordWasAsked)
341 {
342 Encrypted = t.OpenCallbackSpec->PasswordIsDefined;
343 Password = t.OpenCallbackSpec->Password;
344 }
345
346 if (t.Result == S_OK)
347 {
348 Library.Attach(library.Detach());
349 // Folder.Attach(t.Folder.Detach());
350 Folder = t.Folder;
351 }
352
353 return t.Result;
354 }
355
356 return S_FALSE;
357 }
358