Home | History | Annotate | Download | only in 7z
      1 // 7zFolderOutStream.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "7zFolderOutStream.h"
      6 
      7 namespace NArchive {
      8 namespace N7z {
      9 
     10 CFolderOutStream::CFolderOutStream()
     11 {
     12   _crcStreamSpec = new COutStreamWithCRC;
     13   _crcStream = _crcStreamSpec;
     14 }
     15 
     16 HRESULT CFolderOutStream::Init(
     17     const CArchiveDatabaseEx *db,
     18     UInt32 ref2Offset, UInt32 startIndex,
     19     const CBoolVector *extractStatuses,
     20     IArchiveExtractCallback *extractCallback,
     21     bool testMode, bool checkCrc)
     22 {
     23   _db = db;
     24   _ref2Offset = ref2Offset;
     25   _startIndex = startIndex;
     26 
     27   _extractStatuses = extractStatuses;
     28   _extractCallback = extractCallback;
     29   _testMode = testMode;
     30   _checkCrc = checkCrc;
     31 
     32   _currentIndex = 0;
     33   _fileIsOpen = false;
     34   return ProcessEmptyFiles();
     35 }
     36 
     37 HRESULT CFolderOutStream::OpenFile()
     38 {
     39   Int32 askMode = ((*_extractStatuses)[_currentIndex]) ? (_testMode ?
     40       NExtract::NAskMode::kTest :
     41       NExtract::NAskMode::kExtract) :
     42       NExtract::NAskMode::kSkip;
     43   CMyComPtr<ISequentialOutStream> realOutStream;
     44   UInt32 index = _startIndex + _currentIndex;
     45   RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode));
     46   _crcStreamSpec->SetStream(realOutStream);
     47   _crcStreamSpec->Init(_checkCrc);
     48   _fileIsOpen = true;
     49   const CFileItem &fi = _db->Files[index];
     50   _rem = fi.Size;
     51   if (askMode == NExtract::NAskMode::kExtract && !realOutStream &&
     52       !_db->IsItemAnti(index) && !fi.IsDir)
     53     askMode = NExtract::NAskMode::kSkip;
     54   return _extractCallback->PrepareOperation(askMode);
     55 }
     56 
     57 HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res)
     58 {
     59   _crcStreamSpec->ReleaseStream();
     60   _fileIsOpen = false;
     61   _currentIndex++;
     62   return _extractCallback->SetOperationResult(res);
     63 }
     64 
     65 HRESULT CFolderOutStream::CloseFileAndSetResult()
     66 {
     67   const CFileItem &fi = _db->Files[_startIndex + _currentIndex];
     68   return CloseFileAndSetResult(
     69       (fi.IsDir || !fi.CrcDefined || !_checkCrc || fi.Crc == _crcStreamSpec->GetCRC()) ?
     70       NExtract::NOperationResult::kOK :
     71       NExtract::NOperationResult::kCRCError);
     72 }
     73 
     74 HRESULT CFolderOutStream::ProcessEmptyFiles()
     75 {
     76   while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
     77   {
     78     RINOK(OpenFile());
     79     RINOK(CloseFileAndSetResult());
     80   }
     81   return S_OK;
     82 }
     83 
     84 STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
     85 {
     86   if (processedSize != NULL)
     87     *processedSize = 0;
     88   while (size != 0)
     89   {
     90     if (_fileIsOpen)
     91     {
     92       UInt32 cur = size < _rem ? size : (UInt32)_rem;
     93       RINOK(_crcStream->Write(data, cur, &cur));
     94       if (cur == 0)
     95         break;
     96       data = (const Byte *)data + cur;
     97       size -= cur;
     98       _rem -= cur;
     99       if (processedSize != NULL)
    100         *processedSize += cur;
    101       if (_rem == 0)
    102       {
    103         RINOK(CloseFileAndSetResult());
    104         RINOK(ProcessEmptyFiles());
    105         continue;
    106       }
    107     }
    108     else
    109     {
    110       RINOK(ProcessEmptyFiles());
    111       if (_currentIndex == _extractStatuses->Size())
    112       {
    113         // we support partial extracting
    114         if (processedSize != NULL)
    115           *processedSize += size;
    116         break;
    117       }
    118       RINOK(OpenFile());
    119     }
    120   }
    121   return S_OK;
    122 }
    123 
    124 STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
    125 {
    126   *value = 0;
    127   if ((int)subStream >= _extractStatuses->Size())
    128     return S_FALSE;
    129   *value = _db->Files[_startIndex + (int)subStream].Size;
    130   return S_OK;
    131 }
    132 
    133 HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
    134 {
    135   while (_currentIndex < _extractStatuses->Size())
    136   {
    137     if (_fileIsOpen)
    138     {
    139       RINOK(CloseFileAndSetResult(resultEOperationResult));
    140     }
    141     else
    142     {
    143       RINOK(OpenFile());
    144     }
    145   }
    146   return S_OK;
    147 }
    148 
    149 }}
    150