1// 7zFolderInStream.cpp
2
3#include "StdAfx.h"
4
5#include "7zFolderInStream.h"
6
7namespace NArchive {
8namespace N7z {
9
10CFolderInStream::CFolderInStream()
11{
12  _inStreamWithHashSpec = new CSequentialInStreamWithCRC;
13  _inStreamWithHash = _inStreamWithHashSpec;
14}
15
16void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
17    const UInt32 *fileIndices, UInt32 numFiles)
18{
19  _updateCallback = updateCallback;
20  _numFiles = numFiles;
21  _fileIndex = 0;
22  _fileIndices = fileIndices;
23  Processed.Clear();
24  CRCs.Clear();
25  Sizes.Clear();
26  _fileIsOpen = false;
27  _currentSizeIsDefined = false;
28}
29
30HRESULT CFolderInStream::OpenStream()
31{
32  _filePos = 0;
33  while (_fileIndex < _numFiles)
34  {
35    CMyComPtr<ISequentialInStream> stream;
36    HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream);
37    if (result != S_OK && result != S_FALSE)
38      return result;
39    _fileIndex++;
40    _inStreamWithHashSpec->SetStream(stream);
41    _inStreamWithHashSpec->Init();
42    if (stream)
43    {
44      _fileIsOpen = true;
45      CMyComPtr<IStreamGetSize> streamGetSize;
46      stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
47      if (streamGetSize)
48      {
49        RINOK(streamGetSize->GetSize(&_currentSize));
50        _currentSizeIsDefined = true;
51      }
52      return S_OK;
53    }
54    RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
55    Sizes.Add(0);
56    Processed.Add(result == S_OK);
57    AddDigest();
58  }
59  return S_OK;
60}
61
62void CFolderInStream::AddDigest()
63{
64  CRCs.Add(_inStreamWithHashSpec->GetCRC());
65}
66
67HRESULT CFolderInStream::CloseStream()
68{
69  RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
70  _inStreamWithHashSpec->ReleaseStream();
71  _fileIsOpen = false;
72  _currentSizeIsDefined = false;
73  Processed.Add(true);
74  Sizes.Add(_filePos);
75  AddDigest();
76  return S_OK;
77}
78
79STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
80{
81  if (processedSize != 0)
82    *processedSize = 0;
83  while (size > 0)
84  {
85    if (_fileIsOpen)
86    {
87      UInt32 processed2;
88      RINOK(_inStreamWithHash->Read(data, size, &processed2));
89      if (processed2 == 0)
90      {
91        RINOK(CloseStream());
92        continue;
93      }
94      if (processedSize != 0)
95        *processedSize = processed2;
96      _filePos += processed2;
97      break;
98    }
99    if (_fileIndex >= _numFiles)
100      break;
101    RINOK(OpenStream());
102  }
103  return S_OK;
104}
105
106STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
107{
108  *value = 0;
109  unsigned index2 = (unsigned)subStream;
110  if (subStream > Sizes.Size())
111    return E_FAIL;
112  if (index2 < Sizes.Size())
113  {
114    *value = Sizes[index2];
115    return S_OK;
116  }
117  if (!_currentSizeIsDefined)
118    return S_FALSE;
119  *value = _currentSize;
120  return S_OK;
121}
122
123}}
124