misc/libphysfs/lzma/CPP/7zip/Archive/7z/7zExtract.cpp
changeset 12213 bb5522e88ab2
equal deleted inserted replaced
12212:ea891871f481 12213:bb5522e88ab2
       
     1 // 7zExtract.cpp
       
     2 
       
     3 #include "StdAfx.h"
       
     4 
       
     5 #include "7zHandler.h"
       
     6 #include "7zFolderOutStream.h"
       
     7 #include "7zDecode.h"
       
     8 // #include "7z1Decode.h"
       
     9 
       
    10 #include "../../../Common/ComTry.h"
       
    11 #include "../../Common/StreamObjects.h"
       
    12 #include "../../Common/ProgressUtils.h"
       
    13 #include "../../Common/LimitedStreams.h"
       
    14 
       
    15 namespace NArchive {
       
    16 namespace N7z {
       
    17 
       
    18 struct CExtractFolderInfo
       
    19 {
       
    20   #ifdef _7Z_VOL
       
    21   int VolumeIndex;
       
    22   #endif
       
    23   CNum FileIndex;
       
    24   CNum FolderIndex;
       
    25   CBoolVector ExtractStatuses;
       
    26   UInt64 UnPackSize;
       
    27   CExtractFolderInfo(
       
    28     #ifdef _7Z_VOL
       
    29     int volumeIndex, 
       
    30     #endif
       
    31     CNum fileIndex, CNum folderIndex): 
       
    32     #ifdef _7Z_VOL
       
    33     VolumeIndex(volumeIndex),
       
    34     #endif
       
    35     FileIndex(fileIndex),
       
    36     FolderIndex(folderIndex), 
       
    37     UnPackSize(0) 
       
    38   {
       
    39     if (fileIndex != kNumNoIndex)
       
    40     {
       
    41       ExtractStatuses.Reserve(1);
       
    42       ExtractStatuses.Add(true);
       
    43     }
       
    44   };
       
    45 };
       
    46 
       
    47 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
       
    48     Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
       
    49 {
       
    50   COM_TRY_BEGIN
       
    51   bool testMode = (testModeSpec != 0);
       
    52   CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
       
    53   UInt64 importantTotalUnPacked = 0;
       
    54 
       
    55   bool allFilesMode = (numItems == UInt32(-1));
       
    56   if (allFilesMode)
       
    57     numItems = 
       
    58     #ifdef _7Z_VOL
       
    59     _refs.Size();
       
    60     #else
       
    61     _database.Files.Size();
       
    62     #endif
       
    63 
       
    64   if(numItems == 0)
       
    65     return S_OK;
       
    66 
       
    67   /*
       
    68   if(_volumes.Size() != 1)
       
    69     return E_FAIL;
       
    70   const CVolume &volume = _volumes.Front();
       
    71   const CArchiveDatabaseEx &_database = volume.Database;
       
    72   IInStream *_inStream = volume.Stream;
       
    73   */
       
    74   
       
    75   CObjectVector<CExtractFolderInfo> extractFolderInfoVector;
       
    76   for(UInt32 ii = 0; ii < numItems; ii++)
       
    77   {
       
    78     // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex];
       
    79     UInt32 ref2Index = allFilesMode ? ii : indices[ii];
       
    80     // const CRef2 &ref2 = _refs[ref2Index];
       
    81 
       
    82     // for(UInt32 ri = 0; ri < ref2.Refs.Size(); ri++)
       
    83     {
       
    84       #ifdef _7Z_VOL
       
    85       // const CRef &ref = ref2.Refs[ri];
       
    86       const CRef &ref = _refs[ref2Index];
       
    87 
       
    88       int volumeIndex = ref.VolumeIndex;
       
    89       const CVolume &volume = _volumes[volumeIndex];
       
    90       const CArchiveDatabaseEx &database = volume.Database;
       
    91       UInt32 fileIndex = ref.ItemIndex;
       
    92       #else
       
    93       const CArchiveDatabaseEx &database = _database;
       
    94       UInt32 fileIndex = ref2Index;
       
    95       #endif
       
    96 
       
    97       CNum folderIndex = database.FileIndexToFolderIndexMap[fileIndex];
       
    98       if (folderIndex == kNumNoIndex)
       
    99       {
       
   100         extractFolderInfoVector.Add(CExtractFolderInfo(
       
   101             #ifdef _7Z_VOL
       
   102             volumeIndex, 
       
   103             #endif
       
   104             fileIndex, kNumNoIndex));
       
   105         continue;
       
   106       }
       
   107       if (extractFolderInfoVector.IsEmpty() || 
       
   108         folderIndex != extractFolderInfoVector.Back().FolderIndex 
       
   109         #ifdef _7Z_VOL
       
   110         || volumeIndex != extractFolderInfoVector.Back().VolumeIndex
       
   111         #endif
       
   112         )
       
   113       {
       
   114         extractFolderInfoVector.Add(CExtractFolderInfo(
       
   115             #ifdef _7Z_VOL
       
   116             volumeIndex, 
       
   117             #endif
       
   118             kNumNoIndex, folderIndex));
       
   119         const CFolder &folderInfo = database.Folders[folderIndex];
       
   120         UInt64 unPackSize = folderInfo.GetUnPackSize();
       
   121         importantTotalUnPacked += unPackSize;
       
   122         extractFolderInfoVector.Back().UnPackSize = unPackSize;
       
   123       }
       
   124       
       
   125       CExtractFolderInfo &efi = extractFolderInfoVector.Back();
       
   126       
       
   127       // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex];
       
   128       CNum startIndex = database.FolderStartFileIndex[folderIndex];
       
   129       for (CNum index = efi.ExtractStatuses.Size();
       
   130           index <= fileIndex - startIndex; index++)
       
   131       {
       
   132         // UInt64 unPackSize = _database.Files[startIndex + index].UnPackSize;
       
   133         // Count partial_folder_size
       
   134         // efi.UnPackSize += unPackSize;
       
   135         // importantTotalUnPacked += unPackSize;
       
   136         efi.ExtractStatuses.Add(index == fileIndex - startIndex);
       
   137       }
       
   138     }
       
   139   }
       
   140 
       
   141   extractCallback->SetTotal(importantTotalUnPacked);
       
   142 
       
   143   CDecoder decoder(
       
   144     #ifdef _ST_MODE
       
   145     false
       
   146     #else
       
   147     true
       
   148     #endif
       
   149     );
       
   150   // CDecoder1 decoder;
       
   151 
       
   152   UInt64 currentTotalPacked = 0;
       
   153   UInt64 currentTotalUnPacked = 0;
       
   154   UInt64 totalFolderUnPacked;
       
   155   UInt64 totalFolderPacked;
       
   156 
       
   157   CLocalProgress *lps = new CLocalProgress;
       
   158   CMyComPtr<ICompressProgressInfo> progress = lps;
       
   159   lps->Init(extractCallback, false);
       
   160 
       
   161   for(int i = 0; i < extractFolderInfoVector.Size(); i++, 
       
   162       currentTotalUnPacked += totalFolderUnPacked,
       
   163       currentTotalPacked += totalFolderPacked)
       
   164   {
       
   165     lps->OutSize = currentTotalUnPacked;
       
   166     lps->InSize = currentTotalPacked;
       
   167     RINOK(lps->SetCur());
       
   168     
       
   169     const CExtractFolderInfo &efi = extractFolderInfoVector[i];
       
   170     totalFolderUnPacked = efi.UnPackSize;
       
   171 
       
   172     totalFolderPacked = 0;
       
   173 
       
   174     CFolderOutStream *folderOutStream = new CFolderOutStream;
       
   175     CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
       
   176 
       
   177     #ifdef _7Z_VOL
       
   178     const CVolume &volume = _volumes[efi.VolumeIndex];
       
   179     const CArchiveDatabaseEx &database = volume.Database;
       
   180     #else
       
   181     const CArchiveDatabaseEx &database = _database;
       
   182     #endif
       
   183 
       
   184     CNum startIndex;
       
   185     if (efi.FileIndex != kNumNoIndex)
       
   186       startIndex = efi.FileIndex;
       
   187     else
       
   188       startIndex = database.FolderStartFileIndex[efi.FolderIndex];
       
   189 
       
   190 
       
   191     HRESULT result = folderOutStream->Init(&database, 
       
   192         #ifdef _7Z_VOL
       
   193         volume.StartRef2Index, 
       
   194         #else
       
   195         0,
       
   196         #endif
       
   197         startIndex, 
       
   198         &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0);
       
   199 
       
   200     RINOK(result);
       
   201 
       
   202     if (efi.FileIndex != kNumNoIndex)
       
   203       continue;
       
   204 
       
   205     CNum folderIndex = efi.FolderIndex;
       
   206     const CFolder &folderInfo = database.Folders[folderIndex];
       
   207 
       
   208     totalFolderPacked = _database.GetFolderFullPackSize(folderIndex);
       
   209 
       
   210     CNum packStreamIndex = database.FolderStartPackStreamIndex[folderIndex];
       
   211     UInt64 folderStartPackPos = database.GetFolderStreamPos(folderIndex, 0);
       
   212 
       
   213     #ifndef _NO_CRYPTO
       
   214     CMyComPtr<ICryptoGetTextPassword> getTextPassword;
       
   215     if (extractCallback)
       
   216       extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
       
   217     #endif
       
   218 
       
   219     try
       
   220     {
       
   221       HRESULT result = decoder.Decode(
       
   222           EXTERNAL_CODECS_VARS
       
   223           #ifdef _7Z_VOL
       
   224           volume.Stream,
       
   225           #else
       
   226           _inStream,
       
   227           #endif
       
   228           folderStartPackPos, 
       
   229           &database.PackSizes[packStreamIndex],
       
   230           folderInfo,
       
   231           outStream,
       
   232           progress
       
   233           #ifndef _NO_CRYPTO
       
   234           , getTextPassword
       
   235           #endif
       
   236           #ifdef COMPRESS_MT
       
   237           , true, _numThreads
       
   238           #endif
       
   239           );
       
   240 
       
   241       if (result == S_FALSE)
       
   242       {
       
   243         RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
       
   244         continue;
       
   245       }
       
   246       if (result == E_NOTIMPL)
       
   247       {
       
   248         RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
       
   249         continue;
       
   250       }
       
   251       if (result != S_OK)
       
   252         return result;
       
   253       if (folderOutStream->WasWritingFinished() != S_OK)
       
   254       {
       
   255         RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
       
   256         continue;
       
   257       }
       
   258     }
       
   259     catch(...)
       
   260     {
       
   261       RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
       
   262       continue;
       
   263     }
       
   264   }
       
   265   return S_OK;
       
   266   COM_TRY_END
       
   267 }
       
   268 
       
   269 }}