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