1 // StreamObjects.cpp 2 3 #include "StdAfx.h" 4 5 #include "../../../C/Alloc.h" 6 7 #include "StreamObjects.h" 8 9 STDMETHODIMP 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 27 STDMETHODIMP 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 41 void CByteDynBuffer::Free() 42 { 43 free(_buf); 44 _buf = 0; 45 _capacity = 0; 46 } 47 48 bool 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 68 Byte *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 78 void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const 79 { 80 dest.SetCapacity(_size); 81 memcpy(dest, _buffer, _size); 82 } 83 84 STDMETHODIMP 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 100 STDMETHODIMP 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 112 STDMETHODIMP 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 122 static const UInt64 kEmptyTag = (UInt64)(Int64)-1; 123 124 void CCachedInStream::Free() 125 { 126 MyFree(_tags); 127 _tags = 0; 128 MidFree(_data); 129 _data = 0; 130 } 131 132 bool 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 158 void 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 167 STDMETHODIMP 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 209 STDMETHODIMP 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