// MultiStream.cpp | |
#include "StdAfx.h" | |
#include "MultiStream.h" | |
STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize) | |
{ | |
if (processedSize) | |
*processedSize = 0; | |
if (size == 0) | |
return S_OK; | |
if (_pos >= _totalLength) | |
return S_OK; | |
{ | |
unsigned left = 0, mid = _streamIndex, right = Streams.Size(); | |
for (;;) | |
{ | |
CSubStreamInfo &m = Streams[mid]; | |
if (_pos < m.GlobalOffset) | |
right = mid; | |
else if (_pos >= m.GlobalOffset + m.Size) | |
left = mid + 1; | |
else | |
{ | |
_streamIndex = mid; | |
break; | |
} | |
mid = (left + right) / 2; | |
} | |
_streamIndex = mid; | |
} | |
CSubStreamInfo &s = Streams[_streamIndex]; | |
UInt64 localPos = _pos - s.GlobalOffset; | |
if (localPos != s.LocalPos) | |
{ | |
RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos)); | |
} | |
UInt64 rem = s.Size - localPos; | |
if (size > rem) | |
size = (UInt32)rem; | |
HRESULT result = s.Stream->Read(data, size, &size); | |
_pos += size; | |
s.LocalPos += size; | |
if (processedSize) | |
*processedSize = size; | |
return result; | |
} | |
STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) | |
{ | |
switch (seekOrigin) | |
{ | |
case STREAM_SEEK_SET: break; | |
case STREAM_SEEK_CUR: offset += _pos; break; | |
case STREAM_SEEK_END: offset += _totalLength; break; | |
default: return STG_E_INVALIDFUNCTION; | |
} | |
if (offset < 0) | |
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; | |
_pos = offset; | |
if (newPosition) | |
*newPosition = offset; | |
return S_OK; | |
} | |
/* | |
class COutVolumeStream: | |
public ISequentialOutStream, | |
public CMyUnknownImp | |
{ | |
unsigned _volIndex; | |
UInt64 _volSize; | |
UInt64 _curPos; | |
CMyComPtr<ISequentialOutStream> _volumeStream; | |
COutArchive _archive; | |
CCRC _crc; | |
public: | |
MY_UNKNOWN_IMP | |
CFileItem _file; | |
CUpdateOptions _options; | |
CMyComPtr<IArchiveUpdateCallback2> VolumeCallback; | |
void Init(IArchiveUpdateCallback2 *volumeCallback, | |
const UString &name) | |
{ | |
_file.Name = name; | |
_file.IsStartPosDefined = true; | |
_file.StartPos = 0; | |
VolumeCallback = volumeCallback; | |
_volIndex = 0; | |
_volSize = 0; | |
} | |
HRESULT Flush(); | |
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); | |
}; | |
HRESULT COutVolumeStream::Flush() | |
{ | |
if (_volumeStream) | |
{ | |
_file.UnPackSize = _curPos; | |
_file.FileCRC = _crc.GetDigest(); | |
RINOK(WriteVolumeHeader(_archive, _file, _options)); | |
_archive.Close(); | |
_volumeStream.Release(); | |
_file.StartPos += _file.UnPackSize; | |
} | |
return S_OK; | |
} | |
*/ | |
/* | |
STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize) | |
{ | |
if(processedSize != NULL) | |
*processedSize = 0; | |
while(size > 0) | |
{ | |
if (_streamIndex >= Streams.Size()) | |
{ | |
CSubStreamInfo subStream; | |
RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size)); | |
RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream)); | |
subStream.Pos = 0; | |
Streams.Add(subStream); | |
continue; | |
} | |
CSubStreamInfo &subStream = Streams[_streamIndex]; | |
if (_offsetPos >= subStream.Size) | |
{ | |
_offsetPos -= subStream.Size; | |
_streamIndex++; | |
continue; | |
} | |
if (_offsetPos != subStream.Pos) | |
{ | |
CMyComPtr<IOutStream> outStream; | |
RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream)); | |
RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL)); | |
subStream.Pos = _offsetPos; | |
} | |
UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos); | |
UInt32 realProcessed; | |
RINOK(subStream.Stream->Write(data, curSize, &realProcessed)); | |
data = (void *)((Byte *)data + realProcessed); | |
size -= realProcessed; | |
subStream.Pos += realProcessed; | |
_offsetPos += realProcessed; | |
_absPos += realProcessed; | |
if (_absPos > _length) | |
_length = _absPos; | |
if(processedSize != NULL) | |
*processedSize += realProcessed; | |
if (subStream.Pos == subStream.Size) | |
{ | |
_streamIndex++; | |
_offsetPos = 0; | |
} | |
if (realProcessed != curSize && realProcessed == 0) | |
return E_FAIL; | |
} | |
return S_OK; | |
} | |
STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) | |
{ | |
switch (seekOrigin) | |
{ | |
case STREAM_SEEK_SET: break; | |
case STREAM_SEEK_CUR: offset += _absPos; break; | |
case STREAM_SEEK_END: offset += _length; break; | |
default: return STG_E_INVALIDFUNCTION; | |
} | |
if (offset < 0) | |
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; | |
_absPos = offset; | |
_offsetPos = _absPos; | |
_streamIndex = 0; | |
if (newPosition) | |
*newPosition = offset; | |
return S_OK; | |
} | |
*/ |