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