xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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