1 // 7zFolderInStream.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "7zFolderInStream.h"
6 
7 namespace NArchive {
8 namespace N7z {
9 
Init(IArchiveUpdateCallback * updateCallback,const UInt32 * indexes,unsigned numFiles)10 void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
11     const UInt32 *indexes, unsigned numFiles)
12 {
13   _updateCallback = updateCallback;
14   _indexes = indexes;
15   _numFiles = numFiles;
16   _index = 0;
17 
18   Processed.ClearAndReserve(numFiles);
19   CRCs.ClearAndReserve(numFiles);
20   Sizes.ClearAndReserve(numFiles);
21 
22   _pos = 0;
23   _crc = CRC_INIT_VAL;
24   _size_Defined = false;
25   _size = 0;
26 
27   _stream.Release();
28 }
29 
OpenStream()30 HRESULT CFolderInStream::OpenStream()
31 {
32   _pos = 0;
33   _crc = CRC_INIT_VAL;
34   _size_Defined = false;
35   _size = 0;
36 
37   while (_index < _numFiles)
38   {
39     CMyComPtr<ISequentialInStream> stream;
40     HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream);
41     if (result != S_OK)
42     {
43       if (result != S_FALSE)
44         return result;
45     }
46 
47     _stream = stream;
48 
49     if (stream)
50     {
51       CMyComPtr<IStreamGetSize> streamGetSize;
52       stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
53       if (streamGetSize)
54       {
55         if (streamGetSize->GetSize(&_size) == S_OK)
56           _size_Defined = true;
57       }
58       return S_OK;
59     }
60 
61     _index++;
62     RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
63     AddFileInfo(result == S_OK);
64   }
65   return S_OK;
66 }
67 
AddFileInfo(bool isProcessed)68 void CFolderInStream::AddFileInfo(bool isProcessed)
69 {
70   Processed.Add(isProcessed);
71   Sizes.Add(_pos);
72   CRCs.Add(CRC_GET_DIGEST(_crc));
73 }
74 
Read(void * data,UInt32 size,UInt32 * processedSize)75 STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
76 {
77   if (processedSize)
78     *processedSize = 0;
79   while (size != 0)
80   {
81     if (_stream)
82     {
83       UInt32 cur = size;
84       const UInt32 kMax = (UInt32)1 << 20;
85       if (cur > kMax)
86         cur = kMax;
87       RINOK(_stream->Read(data, cur, &cur));
88       if (cur != 0)
89       {
90         _crc = CrcUpdate(_crc, data, cur);
91         _pos += cur;
92         if (processedSize)
93           *processedSize = cur;
94         return S_OK;
95       }
96 
97       _stream.Release();
98       _index++;
99       AddFileInfo(true);
100 
101       _pos = 0;
102       _crc = CRC_INIT_VAL;
103       _size_Defined = false;
104       _size = 0;
105 
106       RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
107     }
108 
109     if (_index >= _numFiles)
110       break;
111     RINOK(OpenStream());
112   }
113   return S_OK;
114 }
115 
GetSubStreamSize(UInt64 subStream,UInt64 * value)116 STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
117 {
118   *value = 0;
119   if (subStream > Sizes.Size())
120     return S_FALSE; // E_FAIL;
121 
122   unsigned index = (unsigned)subStream;
123   if (index < Sizes.Size())
124   {
125     *value = Sizes[index];
126     return S_OK;
127   }
128 
129   if (!_size_Defined)
130   {
131     *value = _pos;
132     return S_FALSE;
133   }
134 
135   *value = (_pos > _size ? _pos : _size);
136   return S_OK;
137 }
138 
139 }}
140