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