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