| // 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; | |
| } |