1// StreamObjects.cpp 2 3#include "StdAfx.h" 4 5#include "../../../C/Alloc.h" 6 7#include "StreamObjects.h" 8 9STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 10{ 11 if (processedSize) 12 *processedSize = 0; 13 if (size == 0) 14 return S_OK; 15 if (_pos > _size) 16 return E_FAIL; 17 size_t rem = _size - (size_t)_pos; 18 if (rem > size) 19 rem = (size_t)size; 20 memcpy(data, _data + (size_t)_pos, rem); 21 _pos += rem; 22 if (processedSize) 23 *processedSize = (UInt32)rem; 24 return S_OK; 25} 26 27STDMETHODIMP CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 28{ 29 switch(seekOrigin) 30 { 31 case STREAM_SEEK_SET: _pos = offset; break; 32 case STREAM_SEEK_CUR: _pos += offset; break; 33 case STREAM_SEEK_END: _pos = _size + offset; break; 34 default: return STG_E_INVALIDFUNCTION; 35 } 36 if (newPosition) 37 *newPosition = _pos; 38 return S_OK; 39} 40 41void CByteDynBuffer::Free() 42{ 43 free(_buf); 44 _buf = 0; 45 _capacity = 0; 46} 47 48bool CByteDynBuffer::EnsureCapacity(size_t cap) 49{ 50 if (cap <= _capacity) 51 return true; 52 size_t delta; 53 if (_capacity > 64) 54 delta = _capacity / 4; 55 else if (_capacity > 8) 56 delta = 16; 57 else 58 delta = 4; 59 cap = MyMax(_capacity + delta, cap); 60 Byte *buf = (Byte *)realloc(_buf, cap); 61 if (!buf) 62 return false; 63 _buf = buf; 64 _capacity = cap; 65 return true; 66} 67 68Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize) 69{ 70 addSize += _size; 71 if (addSize < _size) 72 return NULL; 73 if (!_buffer.EnsureCapacity(addSize)) 74 return NULL; 75 return (Byte *)_buffer + _size; 76} 77 78void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const 79{ 80 dest.SetCapacity(_size); 81 memcpy(dest, _buffer, _size); 82} 83 84STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 85{ 86 if (processedSize) 87 *processedSize = 0; 88 if (size == 0) 89 return S_OK; 90 Byte *buf = GetBufPtrForWriting(size); 91 if (!buf) 92 return E_OUTOFMEMORY; 93 memcpy(buf, data, size); 94 UpdateSize(size); 95 if (processedSize) 96 *processedSize = size; 97 return S_OK; 98} 99 100STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 101{ 102 size_t rem = _size - _pos; 103 if (rem > size) 104 rem = (size_t)size; 105 memcpy(_buffer + _pos, data, rem); 106 _pos += rem; 107 if (processedSize) 108 *processedSize = (UInt32)rem; 109 return (rem != 0 || size == 0) ? S_OK : E_FAIL; 110} 111 112STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize) 113{ 114 UInt32 realProcessedSize; 115 HRESULT result = _stream->Write(data, size, &realProcessedSize); 116 _size += realProcessedSize; 117 if (processedSize) 118 *processedSize = realProcessedSize; 119 return result; 120} 121 122static const UInt64 kEmptyTag = (UInt64)(Int64)-1; 123 124void CCachedInStream::Free() 125{ 126 MyFree(_tags); 127 _tags = 0; 128 MidFree(_data); 129 _data = 0; 130} 131 132bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) 133{ 134 unsigned sizeLog = blockSizeLog + numBlocksLog; 135 if (sizeLog >= sizeof(size_t) * 8) 136 return false; 137 size_t dataSize = (size_t)1 << sizeLog; 138 if (_data == 0 || dataSize != _dataSize) 139 { 140 MidFree(_data); 141 _data = (Byte *)MidAlloc(dataSize); 142 if (_data == 0) 143 return false; 144 _dataSize = dataSize; 145 } 146 if (_tags == 0 || numBlocksLog != _numBlocksLog) 147 { 148 MyFree(_tags); 149 _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog); 150 if (_tags == 0) 151 return false; 152 _numBlocksLog = numBlocksLog; 153 } 154 _blockSizeLog = blockSizeLog; 155 return true; 156} 157 158void CCachedInStream::Init(UInt64 size) 159{ 160 _size = size; 161 _pos = 0; 162 size_t numBlocks = (size_t)1 << _numBlocksLog; 163 for (size_t i = 0; i < numBlocks; i++) 164 _tags[i] = kEmptyTag; 165} 166 167STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 168{ 169 if (processedSize) 170 *processedSize = 0; 171 if (size == 0) 172 return S_OK; 173 if (_pos > _size) 174 return E_FAIL; 175 176 { 177 UInt64 rem = _size - _pos; 178 if (size > rem) 179 size = (UInt32)rem; 180 } 181 182 while (size != 0) 183 { 184 UInt64 cacheTag = _pos >> _blockSizeLog; 185 size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1); 186 Byte *p = _data + (cacheIndex << _blockSizeLog); 187 if (_tags[cacheIndex] != cacheTag) 188 { 189 UInt64 remInBlock = _size - (cacheTag << _blockSizeLog); 190 size_t blockSize = (size_t)1 << _blockSizeLog; 191 if (blockSize > remInBlock) 192 blockSize = (size_t)remInBlock; 193 RINOK(ReadBlock(cacheTag, p, blockSize)); 194 _tags[cacheIndex] = cacheTag; 195 } 196 size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1); 197 UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size); 198 memcpy(data, p + offset, cur); 199 if (processedSize) 200 *processedSize += cur; 201 data = (void *)((const Byte *)data + cur); 202 _pos += cur; 203 size -= cur; 204 } 205 206 return S_OK; 207} 208 209STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 210{ 211 switch(seekOrigin) 212 { 213 case STREAM_SEEK_SET: _pos = offset; break; 214 case STREAM_SEEK_CUR: _pos = _pos + offset; break; 215 case STREAM_SEEK_END: _pos = _size + offset; break; 216 default: return STG_E_INVALIDFUNCTION; 217 } 218 if (newPosition != 0) 219 *newPosition = _pos; 220 return S_OK; 221} 222