misc/libphysfs/lzma/CPP/7zip/UI/Common/OpenArchive.cpp
branchui-scaling
changeset 15283 c4fd2813b127
parent 13390 0135e64c6c66
parent 15279 7ab5cf405686
child 15663 d92eeb468dad
equal deleted inserted replaced
13390:0135e64c6c66 15283:c4fd2813b127
     1 // OpenArchive.cpp
       
     2 
       
     3 #include "StdAfx.h"
       
     4 
       
     5 #include "OpenArchive.h"
       
     6 
       
     7 #include "Common/Wildcard.h"
       
     8 
       
     9 #include "Windows/FileName.h"
       
    10 #include "Windows/FileDir.h"
       
    11 #include "Windows/Defs.h"
       
    12 #include "Windows/PropVariant.h"
       
    13 
       
    14 #include "../../Common/FileStreams.h"
       
    15 #include "../../Common/StreamUtils.h"
       
    16 
       
    17 #include "Common/StringConvert.h"
       
    18 
       
    19 #include "DefaultName.h"
       
    20 
       
    21 using namespace NWindows;
       
    22 
       
    23 HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result)
       
    24 {
       
    25   NCOM::CPropVariant prop;
       
    26   RINOK(archive->GetProperty(index, kpidPath, &prop));
       
    27   if(prop.vt == VT_BSTR)
       
    28     result = prop.bstrVal;
       
    29   else if (prop.vt == VT_EMPTY)
       
    30     result.Empty();
       
    31   else
       
    32     return E_FAIL;
       
    33   return S_OK;
       
    34 }
       
    35 
       
    36 HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result)
       
    37 {
       
    38   RINOK(GetArchiveItemPath(archive, index, result));
       
    39   if (result.IsEmpty())
       
    40     result = defaultName;
       
    41   return S_OK;
       
    42 }
       
    43 
       
    44 HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index, 
       
    45     const FILETIME &defaultFileTime, FILETIME &fileTime)
       
    46 {
       
    47   NCOM::CPropVariant prop;
       
    48   RINOK(archive->GetProperty(index, kpidLastWriteTime, &prop));
       
    49   if (prop.vt == VT_FILETIME)
       
    50     fileTime = prop.filetime;
       
    51   else if (prop.vt == VT_EMPTY)
       
    52     fileTime = defaultFileTime;
       
    53   else
       
    54     return E_FAIL;
       
    55   return S_OK;
       
    56 }
       
    57 
       
    58 HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
       
    59 {
       
    60   NCOM::CPropVariant prop;
       
    61   RINOK(archive->GetProperty(index, propID, &prop));
       
    62   if(prop.vt == VT_BOOL)
       
    63     result = VARIANT_BOOLToBool(prop.boolVal);
       
    64   else if (prop.vt == VT_EMPTY)
       
    65     result = false;
       
    66   else
       
    67     return E_FAIL;
       
    68   return S_OK;
       
    69 }
       
    70 
       
    71 HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
       
    72 {
       
    73   return IsArchiveItemProp(archive, index, kpidIsFolder, result);
       
    74 }
       
    75 
       
    76 HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result)
       
    77 {
       
    78   return IsArchiveItemProp(archive, index, kpidIsAnti, result);
       
    79 }
       
    80 
       
    81 // Static-SFX (for Linux) can be big.
       
    82 const UInt64 kMaxCheckStartPosition = 1 << 22;
       
    83 
       
    84 HRESULT ReOpenArchive(IInArchive *archive, const UString &fileName, IArchiveOpenCallback *openArchiveCallback)
       
    85 {
       
    86   CInFileStream *inStreamSpec = new CInFileStream;
       
    87   CMyComPtr<IInStream> inStream(inStreamSpec);
       
    88   inStreamSpec->Open(fileName);
       
    89   return archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback);
       
    90 }
       
    91 
       
    92 #ifndef _SFX
       
    93 static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
       
    94 {
       
    95   for (size_t i = 0; i < size; i++)
       
    96     if (p1[i] != p2[i])
       
    97       return false;
       
    98   return true;
       
    99 }
       
   100 #endif
       
   101 
       
   102 HRESULT OpenArchive(
       
   103     CCodecs *codecs,
       
   104     IInStream *inStream,
       
   105     const UString &fileName, 
       
   106     IInArchive **archiveResult, 
       
   107     int &formatIndex,
       
   108     UString &defaultItemName,
       
   109     IArchiveOpenCallback *openArchiveCallback)
       
   110 {
       
   111   *archiveResult = NULL;
       
   112   UString extension;
       
   113   {
       
   114     int dotPos = fileName.ReverseFind(L'.');
       
   115     if (dotPos >= 0)
       
   116       extension = fileName.Mid(dotPos + 1);
       
   117   }
       
   118   CIntVector orderIndices;
       
   119   int i;
       
   120   int numFinded = 0;
       
   121   for (i = 0; i < codecs->Formats.Size(); i++)
       
   122     if (codecs->Formats[i].FindExtension(extension) >= 0)
       
   123       orderIndices.Insert(numFinded++, i);
       
   124     else
       
   125       orderIndices.Add(i);
       
   126   
       
   127   #ifndef _SFX
       
   128   if (numFinded != 1)
       
   129   {
       
   130     CIntVector orderIndices2;
       
   131     CByteBuffer byteBuffer;
       
   132     const UInt32 kBufferSize = (200 << 10);
       
   133     byteBuffer.SetCapacity(kBufferSize);
       
   134     Byte *buffer = byteBuffer;
       
   135     RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
       
   136     UInt32 processedSize;
       
   137     RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize));
       
   138     for (UInt32 pos = 0; pos < processedSize; pos++)
       
   139     {
       
   140       for (int i = 0; i < orderIndices.Size(); i++)
       
   141       {
       
   142         int index = orderIndices[i];
       
   143         const CArcInfoEx &ai = codecs->Formats[index];
       
   144         const CByteBuffer &sig = ai.StartSignature;
       
   145         if (sig.GetCapacity() == 0)
       
   146           continue;
       
   147         if (pos + sig.GetCapacity() > processedSize)
       
   148           continue;
       
   149         if (TestSignature(buffer + pos, sig, sig.GetCapacity()))
       
   150         {
       
   151           orderIndices2.Add(index);
       
   152           orderIndices.Delete(i--);
       
   153         }
       
   154       }
       
   155     }
       
   156     orderIndices2 += orderIndices;
       
   157     orderIndices = orderIndices2;
       
   158   }
       
   159   else if (extension == L"000" || extension == L"001")
       
   160   {
       
   161     CByteBuffer byteBuffer;
       
   162     const UInt32 kBufferSize = (1 << 10);
       
   163     byteBuffer.SetCapacity(kBufferSize);
       
   164     Byte *buffer = byteBuffer;
       
   165     RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
       
   166     UInt32 processedSize;
       
   167     RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize));
       
   168     if (processedSize >= 16)
       
   169     {
       
   170       Byte kRarHeader[] = {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00};
       
   171       if (TestSignature(buffer, kRarHeader, 7) && buffer[9] == 0x73 && (buffer[10] && 1) != 0)
       
   172       {
       
   173         for (int i = 0; i < orderIndices.Size(); i++)
       
   174         {
       
   175           int index = orderIndices[i];
       
   176           const CArcInfoEx &ai = codecs->Formats[index];
       
   177           if (ai.Name.CompareNoCase(L"rar") != 0)
       
   178             continue;
       
   179           orderIndices.Delete(i--);
       
   180           orderIndices.Insert(0, index);
       
   181           break;
       
   182         }
       
   183       }
       
   184     }
       
   185   }
       
   186   #endif
       
   187 
       
   188   HRESULT badResult = S_OK;
       
   189   for(i = 0; i < orderIndices.Size(); i++)
       
   190   {
       
   191     inStream->Seek(0, STREAM_SEEK_SET, NULL);
       
   192 
       
   193     CMyComPtr<IInArchive> archive;
       
   194 
       
   195     formatIndex = orderIndices[i];
       
   196     RINOK(codecs->CreateInArchive(formatIndex, archive));
       
   197     if (!archive)
       
   198       continue;
       
   199 
       
   200     #ifdef EXTERNAL_CODECS
       
   201     {
       
   202       CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
       
   203       archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
       
   204       if (setCompressCodecsInfo)
       
   205       {
       
   206         RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
       
   207       }
       
   208     }
       
   209     #endif
       
   210 
       
   211     HRESULT result = archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback);
       
   212     if (result == S_FALSE)
       
   213       continue;
       
   214     if(result != S_OK)
       
   215     {
       
   216       badResult = result;
       
   217       if(result == E_ABORT)
       
   218         break;
       
   219       continue;
       
   220     }
       
   221     *archiveResult = archive.Detach();
       
   222     const CArcInfoEx &format = codecs->Formats[formatIndex];
       
   223     if (format.Exts.Size() == 0)
       
   224     {
       
   225       defaultItemName = GetDefaultName2(fileName, L"", L"");
       
   226     }
       
   227     else
       
   228     {
       
   229       int subExtIndex = format.FindExtension(extension);
       
   230       if (subExtIndex < 0)
       
   231         subExtIndex = 0;
       
   232       defaultItemName = GetDefaultName2(fileName, 
       
   233           format.Exts[subExtIndex].Ext, 
       
   234           format.Exts[subExtIndex].AddExt);
       
   235     }
       
   236     return S_OK;
       
   237   }
       
   238   if (badResult != S_OK)
       
   239     return badResult;
       
   240   return S_FALSE;
       
   241 }
       
   242 
       
   243 HRESULT OpenArchive(
       
   244     CCodecs *codecs,
       
   245     const UString &filePath, 
       
   246     IInArchive **archiveResult, 
       
   247     int &formatIndex,
       
   248     UString &defaultItemName,
       
   249     IArchiveOpenCallback *openArchiveCallback)
       
   250 {
       
   251   CInFileStream *inStreamSpec = new CInFileStream;
       
   252   CMyComPtr<IInStream> inStream(inStreamSpec);
       
   253   if (!inStreamSpec->Open(filePath))
       
   254     return GetLastError();
       
   255   return OpenArchive(codecs, inStream, ExtractFileNameFromPath(filePath),
       
   256     archiveResult, formatIndex,
       
   257     defaultItemName, openArchiveCallback);
       
   258 }
       
   259 
       
   260 static void MakeDefaultName(UString &name)
       
   261 {
       
   262   int dotPos = name.ReverseFind(L'.');
       
   263   if (dotPos < 0)
       
   264     return;
       
   265   UString ext = name.Mid(dotPos + 1);
       
   266   if (ext.IsEmpty())
       
   267     return;
       
   268   for (int pos = 0; pos < ext.Length(); pos++)
       
   269     if (ext[pos] < L'0' || ext[pos] > L'9')
       
   270       return;
       
   271   name = name.Left(dotPos);
       
   272 }
       
   273 
       
   274 HRESULT OpenArchive(
       
   275     CCodecs *codecs,
       
   276     const UString &fileName, 
       
   277     IInArchive **archive0, 
       
   278     IInArchive **archive1, 
       
   279     int &formatIndex0,
       
   280     int &formatIndex1,
       
   281     UString &defaultItemName0,
       
   282     UString &defaultItemName1,
       
   283     IArchiveOpenCallback *openArchiveCallback)
       
   284 {
       
   285   HRESULT result = OpenArchive(codecs, fileName, 
       
   286       archive0, formatIndex0, defaultItemName0, openArchiveCallback);
       
   287   RINOK(result);
       
   288   CMyComPtr<IInArchiveGetStream> getStream;
       
   289   result = (*archive0)->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream);
       
   290   if (result != S_OK || getStream == 0)
       
   291     return S_OK;
       
   292 
       
   293   CMyComPtr<ISequentialInStream> subSeqStream;
       
   294   result = getStream->GetStream(0, &subSeqStream);
       
   295   if (result != S_OK)
       
   296     return S_OK;
       
   297 
       
   298   CMyComPtr<IInStream> subStream;
       
   299   if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK)
       
   300     return S_OK;
       
   301   if (!subStream)
       
   302     return S_OK;
       
   303 
       
   304   UInt32 numItems;
       
   305   RINOK((*archive0)->GetNumberOfItems(&numItems));
       
   306   if (numItems < 1)
       
   307     return S_OK;
       
   308 
       
   309   UString subPath;
       
   310   RINOK(GetArchiveItemPath(*archive0, 0, subPath))
       
   311   if (subPath.IsEmpty())
       
   312   {
       
   313     MakeDefaultName(defaultItemName0);
       
   314     subPath = defaultItemName0;
       
   315     const CArcInfoEx &format = codecs->Formats[formatIndex0];
       
   316     if (format.Name.CompareNoCase(L"7z") == 0)
       
   317     {
       
   318       if (subPath.Right(3).CompareNoCase(L".7z") != 0)
       
   319         subPath += L".7z";
       
   320     }
       
   321   }
       
   322   else
       
   323     subPath = ExtractFileNameFromPath(subPath);
       
   324 
       
   325   CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
       
   326   openArchiveCallback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
       
   327   if (setSubArchiveName)
       
   328     setSubArchiveName->SetSubArchiveName(subPath);
       
   329 
       
   330   result = OpenArchive(codecs, subStream, subPath,
       
   331       archive1, formatIndex1, defaultItemName1, openArchiveCallback);
       
   332   return S_OK;
       
   333 }
       
   334 
       
   335 static void SetCallback(const UString &archiveName,
       
   336     IOpenCallbackUI *openCallbackUI, CMyComPtr<IArchiveOpenCallback> &openCallback)
       
   337 {
       
   338   COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
       
   339   openCallback = openCallbackSpec;
       
   340   openCallbackSpec->Callback = openCallbackUI;
       
   341 
       
   342   UString fullName;
       
   343   int fileNamePartStartIndex;
       
   344   NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
       
   345   openCallbackSpec->Init(
       
   346       fullName.Left(fileNamePartStartIndex), 
       
   347       fullName.Mid(fileNamePartStartIndex));
       
   348 }
       
   349 
       
   350 HRESULT MyOpenArchive(
       
   351     CCodecs *codecs, 
       
   352     const UString &archiveName,
       
   353     IInArchive **archive, UString &defaultItemName, IOpenCallbackUI *openCallbackUI)
       
   354 {
       
   355   CMyComPtr<IArchiveOpenCallback> openCallback;
       
   356   SetCallback(archiveName, openCallbackUI, openCallback);
       
   357   int formatInfo;
       
   358   return OpenArchive(codecs, archiveName, archive, formatInfo, defaultItemName, openCallback);
       
   359 }
       
   360 
       
   361 HRESULT MyOpenArchive(
       
   362     CCodecs *codecs,
       
   363     const UString &archiveName,
       
   364     IInArchive **archive0,
       
   365     IInArchive **archive1,
       
   366     UString &defaultItemName0,
       
   367     UString &defaultItemName1,
       
   368     UStringVector &volumePaths,
       
   369     UInt64 &volumesSize,
       
   370     IOpenCallbackUI *openCallbackUI)
       
   371 {
       
   372   volumesSize = 0;
       
   373   COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
       
   374   CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
       
   375   openCallbackSpec->Callback = openCallbackUI;
       
   376 
       
   377   UString fullName;
       
   378   int fileNamePartStartIndex;
       
   379   NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
       
   380   UString prefix = fullName.Left(fileNamePartStartIndex);
       
   381   UString name = fullName.Mid(fileNamePartStartIndex);
       
   382   openCallbackSpec->Init(prefix, name);
       
   383 
       
   384   int formatIndex0, formatIndex1;
       
   385   RINOK(OpenArchive(codecs, archiveName,
       
   386       archive0, 
       
   387       archive1, 
       
   388       formatIndex0, 
       
   389       formatIndex1, 
       
   390       defaultItemName0,
       
   391       defaultItemName1,
       
   392       openCallback));
       
   393   volumePaths.Add(prefix + name);
       
   394   for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++)
       
   395     volumePaths.Add(prefix + openCallbackSpec->FileNames[i]);
       
   396   volumesSize = openCallbackSpec->TotalSize;
       
   397   return S_OK;
       
   398 }
       
   399 
       
   400 HRESULT CArchiveLink::Close()
       
   401 {
       
   402   if (Archive1 != 0)
       
   403     RINOK(Archive1->Close());
       
   404   if (Archive0 != 0)
       
   405     RINOK(Archive0->Close());
       
   406   IsOpen = false;
       
   407   return S_OK;
       
   408 }
       
   409 
       
   410 void CArchiveLink::Release()
       
   411 {
       
   412   IsOpen = false;
       
   413   Archive1.Release();
       
   414   Archive0.Release();
       
   415 }
       
   416 
       
   417 HRESULT OpenArchive(
       
   418     CCodecs *codecs,
       
   419     const UString &archiveName,
       
   420     CArchiveLink &archiveLink,
       
   421     IArchiveOpenCallback *openCallback)
       
   422 {
       
   423   HRESULT res = OpenArchive(codecs, archiveName, 
       
   424     &archiveLink.Archive0, &archiveLink.Archive1, 
       
   425     archiveLink.FormatIndex0, archiveLink.FormatIndex1, 
       
   426     archiveLink.DefaultItemName0, archiveLink.DefaultItemName1, 
       
   427     openCallback);
       
   428   archiveLink.IsOpen = (res == S_OK);
       
   429   return res;
       
   430 }
       
   431 
       
   432 HRESULT MyOpenArchive(CCodecs *codecs,
       
   433     const UString &archiveName, 
       
   434     CArchiveLink &archiveLink,
       
   435     IOpenCallbackUI *openCallbackUI)
       
   436 {
       
   437   HRESULT res = MyOpenArchive(codecs, archiveName,
       
   438     &archiveLink.Archive0, &archiveLink.Archive1, 
       
   439     archiveLink.DefaultItemName0, archiveLink.DefaultItemName1, 
       
   440     archiveLink.VolumePaths,
       
   441     archiveLink.VolumesSize,
       
   442     openCallbackUI);
       
   443   archiveLink.IsOpen = (res == S_OK);
       
   444   return res;
       
   445 }
       
   446 
       
   447 HRESULT ReOpenArchive(CCodecs *codecs, CArchiveLink &archiveLink, const UString &fileName)
       
   448 {
       
   449   if (archiveLink.GetNumLevels() > 1)
       
   450     return E_NOTIMPL;
       
   451 
       
   452   if (archiveLink.GetNumLevels() == 0)
       
   453     return MyOpenArchive(codecs, fileName, archiveLink, 0);
       
   454 
       
   455   CMyComPtr<IArchiveOpenCallback> openCallback;
       
   456   SetCallback(fileName, NULL, openCallback);
       
   457 
       
   458   HRESULT res = ReOpenArchive(archiveLink.GetArchive(), fileName, openCallback);
       
   459   archiveLink.IsOpen = (res == S_OK);
       
   460   return res;
       
   461 }