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