MultiStream.cpp revision baa3858d3f5d128a5c8466b700098109edcad5f2
1// MultiStream.cpp
2
3#include "StdAfx.h"
4
5#include "MultiStream.h"
6
7STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)
8{
9  if (processedSize)
10    *processedSize = 0;
11  if (size == 0)
12    return S_OK;
13  if (_pos >= _totalLength)
14    return (_pos == _totalLength) ? S_OK : E_FAIL;
15
16  {
17    int left = 0, mid = _streamIndex, right = Streams.Size();
18    for (;;)
19    {
20      CSubStreamInfo &m = Streams[mid];
21      if (_pos < m.GlobalOffset)
22        right = mid;
23      else if (_pos >= m.GlobalOffset + m.Size)
24        left = mid + 1;
25      else
26      {
27        _streamIndex = mid;
28        break;
29      }
30      mid = (left + right) / 2;
31    }
32    _streamIndex = mid;
33  }
34
35  CSubStreamInfo &s = Streams[_streamIndex];
36  UInt64 localPos = _pos - s.GlobalOffset;
37  if (localPos != s.LocalPos)
38  {
39    RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos));
40  }
41  UInt64 rem = s.Size - localPos;
42  if (size > rem)
43    size = (UInt32)rem;
44  HRESULT result = s.Stream->Read(data, size, &size);
45  _pos += size;
46  s.LocalPos += size;
47  if (processedSize)
48    *processedSize = size;
49  return result;
50}
51
52STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
53{
54  switch(seekOrigin)
55  {
56    case STREAM_SEEK_SET: _pos = offset; break;
57    case STREAM_SEEK_CUR: _pos = _pos + offset; break;
58    case STREAM_SEEK_END: _pos = _totalLength + offset; break;
59    default: return STG_E_INVALIDFUNCTION;
60  }
61  if (newPosition != 0)
62    *newPosition = _pos;
63  return S_OK;
64}
65
66
67/*
68class COutVolumeStream:
69  public ISequentialOutStream,
70  public CMyUnknownImp
71{
72  int _volIndex;
73  UInt64 _volSize;
74  UInt64 _curPos;
75  CMyComPtr<ISequentialOutStream> _volumeStream;
76  COutArchive _archive;
77  CCRC _crc;
78
79public:
80  MY_UNKNOWN_IMP
81
82  CFileItem _file;
83  CUpdateOptions _options;
84  CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
85  void Init(IArchiveUpdateCallback2 *volumeCallback,
86      const UString &name)
87  {
88    _file.Name = name;
89    _file.IsStartPosDefined = true;
90    _file.StartPos = 0;
91
92    VolumeCallback = volumeCallback;
93    _volIndex = 0;
94    _volSize = 0;
95  }
96
97  HRESULT Flush();
98  STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
99};
100
101HRESULT COutVolumeStream::Flush()
102{
103  if (_volumeStream)
104  {
105    _file.UnPackSize = _curPos;
106    _file.FileCRC = _crc.GetDigest();
107    RINOK(WriteVolumeHeader(_archive, _file, _options));
108    _archive.Close();
109    _volumeStream.Release();
110    _file.StartPos += _file.UnPackSize;
111  }
112  return S_OK;
113}
114*/
115
116/*
117STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
118{
119  if(processedSize != NULL)
120    *processedSize = 0;
121  while(size > 0)
122  {
123    if (_streamIndex >= Streams.Size())
124    {
125      CSubStreamInfo subStream;
126      RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size));
127      RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream));
128      subStream.Pos = 0;
129      Streams.Add(subStream);
130      continue;
131    }
132    CSubStreamInfo &subStream = Streams[_streamIndex];
133    if (_offsetPos >= subStream.Size)
134    {
135      _offsetPos -= subStream.Size;
136      _streamIndex++;
137      continue;
138    }
139    if (_offsetPos != subStream.Pos)
140    {
141      CMyComPtr<IOutStream> outStream;
142      RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
143      RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
144      subStream.Pos = _offsetPos;
145    }
146
147    UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos);
148    UInt32 realProcessed;
149    RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
150    data = (void *)((Byte *)data + realProcessed);
151    size -= realProcessed;
152    subStream.Pos += realProcessed;
153    _offsetPos += realProcessed;
154    _absPos += realProcessed;
155    if (_absPos > _length)
156      _length = _absPos;
157    if(processedSize != NULL)
158      *processedSize += realProcessed;
159    if (subStream.Pos == subStream.Size)
160    {
161      _streamIndex++;
162      _offsetPos = 0;
163    }
164    if (realProcessed != curSize && realProcessed == 0)
165      return E_FAIL;
166  }
167  return S_OK;
168}
169
170STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
171{
172  if(seekOrigin >= 3)
173    return STG_E_INVALIDFUNCTION;
174  switch(seekOrigin)
175  {
176    case STREAM_SEEK_SET:
177      _absPos = offset;
178      break;
179    case STREAM_SEEK_CUR:
180      _absPos += offset;
181      break;
182    case STREAM_SEEK_END:
183      _absPos = _length + offset;
184      break;
185  }
186  _offsetPos = _absPos;
187  _streamIndex = 0;
188  return S_OK;
189}
190*/
191