// StreamObjects.cpp | |
#include "StdAfx.h" | |
#include <stdlib.h> | |
#include "../../../C/Alloc.h" | |
#include "StreamObjects.h" | |
STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize) | |
{ | |
if (processedSize) | |
*processedSize = 0; | |
if (size == 0) | |
return S_OK; | |
if (_pos >= _size) | |
return S_OK; | |
size_t rem = _size - (size_t)_pos; | |
if (rem > size) | |
rem = (size_t)size; | |
memcpy(data, _data + (size_t)_pos, rem); | |
_pos += rem; | |
if (processedSize) | |
*processedSize = (UInt32)rem; | |
return S_OK; | |
} | |
STDMETHODIMP CBufInStream::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 += _size; break; | |
default: return STG_E_INVALIDFUNCTION; | |
} | |
if (offset < 0) | |
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; | |
_pos = offset; | |
if (newPosition) | |
*newPosition = offset; | |
return S_OK; | |
} | |
/* | |
void Create_BufInStream_WithReference(const void *data, size_t size, ISequentialInStream **stream) | |
{ | |
CBufInStream *inStreamSpec = new CBufInStream; | |
CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec; | |
inStreamSpec->Init((const Byte *)data, size); | |
*stream = streamTemp.Detach(); | |
} | |
*/ | |
void Create_BufInStream_WithNewBuf(const void *data, size_t size, ISequentialInStream **stream) | |
{ | |
CReferenceBuf *referenceBuf = new CReferenceBuf; | |
CMyComPtr<IUnknown> ref = referenceBuf; | |
referenceBuf->Buf.CopyFrom((const Byte *)data, size); | |
CBufInStream *inStreamSpec = new CBufInStream; | |
CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec; | |
inStreamSpec->Init(referenceBuf); | |
*stream = streamTemp.Detach(); | |
} | |
void CByteDynBuffer::Free() throw() | |
{ | |
free(_buf); | |
_buf = 0; | |
_capacity = 0; | |
} | |
bool CByteDynBuffer::EnsureCapacity(size_t cap) throw() | |
{ | |
if (cap <= _capacity) | |
return true; | |
size_t delta; | |
if (_capacity > 64) | |
delta = _capacity / 4; | |
else if (_capacity > 8) | |
delta = 16; | |
else | |
delta = 4; | |
cap = MyMax(_capacity + delta, cap); | |
Byte *buf = (Byte *)realloc(_buf, cap); | |
if (!buf) | |
return false; | |
_buf = buf; | |
_capacity = cap; | |
return true; | |
} | |
Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize) | |
{ | |
addSize += _size; | |
if (addSize < _size) | |
return NULL; | |
if (!_buffer.EnsureCapacity(addSize)) | |
return NULL; | |
return (Byte *)_buffer + _size; | |
} | |
void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const | |
{ | |
dest.CopyFrom((const Byte *)_buffer, _size); | |
} | |
STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) | |
{ | |
if (processedSize) | |
*processedSize = 0; | |
if (size == 0) | |
return S_OK; | |
Byte *buf = GetBufPtrForWriting(size); | |
if (!buf) | |
return E_OUTOFMEMORY; | |
memcpy(buf, data, size); | |
UpdateSize(size); | |
if (processedSize) | |
*processedSize = size; | |
return S_OK; | |
} | |
STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) | |
{ | |
size_t rem = _size - _pos; | |
if (rem > size) | |
rem = (size_t)size; | |
memcpy(_buffer + _pos, data, rem); | |
_pos += rem; | |
if (processedSize) | |
*processedSize = (UInt32)rem; | |
return (rem != 0 || size == 0) ? S_OK : E_FAIL; | |
} | |
STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize) | |
{ | |
UInt32 realProcessedSize; | |
HRESULT result = _stream->Write(data, size, &realProcessedSize); | |
_size += realProcessedSize; | |
if (processedSize) | |
*processedSize = realProcessedSize; | |
return result; | |
} | |
static const UInt64 kEmptyTag = (UInt64)(Int64)-1; | |
void CCachedInStream::Free() throw() | |
{ | |
MyFree(_tags); | |
_tags = 0; | |
MidFree(_data); | |
_data = 0; | |
} | |
bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw() | |
{ | |
unsigned sizeLog = blockSizeLog + numBlocksLog; | |
if (sizeLog >= sizeof(size_t) * 8) | |
return false; | |
size_t dataSize = (size_t)1 << sizeLog; | |
if (_data == 0 || dataSize != _dataSize) | |
{ | |
MidFree(_data); | |
_data = (Byte *)MidAlloc(dataSize); | |
if (_data == 0) | |
return false; | |
_dataSize = dataSize; | |
} | |
if (_tags == 0 || numBlocksLog != _numBlocksLog) | |
{ | |
MyFree(_tags); | |
_tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog); | |
if (_tags == 0) | |
return false; | |
_numBlocksLog = numBlocksLog; | |
} | |
_blockSizeLog = blockSizeLog; | |
return true; | |
} | |
void CCachedInStream::Init(UInt64 size) throw() | |
{ | |
_size = size; | |
_pos = 0; | |
size_t numBlocks = (size_t)1 << _numBlocksLog; | |
for (size_t i = 0; i < numBlocks; i++) | |
_tags[i] = kEmptyTag; | |
} | |
STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) | |
{ | |
if (processedSize) | |
*processedSize = 0; | |
if (size == 0) | |
return S_OK; | |
if (_pos >= _size) | |
return S_OK; | |
{ | |
UInt64 rem = _size - _pos; | |
if (size > rem) | |
size = (UInt32)rem; | |
} | |
while (size != 0) | |
{ | |
UInt64 cacheTag = _pos >> _blockSizeLog; | |
size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1); | |
Byte *p = _data + (cacheIndex << _blockSizeLog); | |
if (_tags[cacheIndex] != cacheTag) | |
{ | |
UInt64 remInBlock = _size - (cacheTag << _blockSizeLog); | |
size_t blockSize = (size_t)1 << _blockSizeLog; | |
if (blockSize > remInBlock) | |
blockSize = (size_t)remInBlock; | |
RINOK(ReadBlock(cacheTag, p, blockSize)); | |
_tags[cacheIndex] = cacheTag; | |
} | |
size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1); | |
UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size); | |
memcpy(data, p + offset, cur); | |
if (processedSize) | |
*processedSize += cur; | |
data = (void *)((const Byte *)data + cur); | |
_pos += cur; | |
size -= cur; | |
} | |
return S_OK; | |
} | |
STDMETHODIMP CCachedInStream::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 += _size; break; | |
default: return STG_E_INVALIDFUNCTION; | |
} | |
if (offset < 0) | |
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; | |
_pos = offset; | |
if (newPosition) | |
*newPosition = offset; | |
return S_OK; | |
} |