1 // LimitedStreams.cpp 2 3 #include "StdAfx.h" 4 5 #include "LimitedStreams.h" 6 #include "../../Common/Defs.h" 7 8 STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 9 { 10 UInt32 realProcessedSize = 0; 11 UInt32 sizeToRead = (UInt32)MyMin((_size - _pos), (UInt64)size); 12 HRESULT result = S_OK; 13 if (sizeToRead > 0) 14 { 15 result = _stream->Read(data, sizeToRead, &realProcessedSize); 16 _pos += realProcessedSize; 17 if (realProcessedSize == 0) 18 _wasFinished = true; 19 } 20 if (processedSize) 21 *processedSize = realProcessedSize; 22 return result; 23 } 24 25 STDMETHODIMP CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 26 { 27 if (processedSize) 28 *processedSize = 0; 29 if (_virtPos >= _size) 30 { 31 // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. 32 return S_OK; 33 // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF 34 } 35 UInt64 rem = _size - _virtPos; 36 if (rem < size) 37 size = (UInt32)rem; 38 UInt64 newPos = _startOffset + _virtPos; 39 if (newPos != _physPos) 40 { 41 _physPos = newPos; 42 RINOK(SeekToPhys()); 43 } 44 HRESULT res = _stream->Read(data, size, &size); 45 if (processedSize) 46 *processedSize = size; 47 _physPos += size; 48 _virtPos += size; 49 return res; 50 } 51 52 STDMETHODIMP CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 53 { 54 switch (seekOrigin) 55 { 56 case STREAM_SEEK_SET: break; 57 case STREAM_SEEK_CUR: offset += _virtPos; break; 58 case STREAM_SEEK_END: offset += _size; break; 59 default: return STG_E_INVALIDFUNCTION; 60 } 61 if (offset < 0) 62 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 63 _virtPos = offset; 64 if (newPosition) 65 *newPosition = _virtPos; 66 return S_OK; 67 } 68 69 HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream) 70 { 71 *resStream = 0; 72 CLimitedInStream *streamSpec = new CLimitedInStream; 73 CMyComPtr<ISequentialInStream> streamTemp = streamSpec; 74 streamSpec->SetStream(inStream); 75 RINOK(streamSpec->InitAndSeek(pos, size)); 76 streamSpec->SeekToStart(); 77 *resStream = streamTemp.Detach(); 78 return S_OK; 79 } 80 81 STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 82 { 83 if (processedSize) 84 *processedSize = 0; 85 if (_virtPos >= Size) 86 return S_OK; 87 88 if (_curRem == 0) 89 { 90 UInt32 blockSize = (UInt32)1 << BlockSizeLog; 91 UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog); 92 UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); 93 UInt32 phyBlock = Vector[virtBlock]; 94 UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock; 95 if (newPos != _physPos) 96 { 97 _physPos = newPos; 98 RINOK(SeekToPhys()); 99 } 100 _curRem = blockSize - offsetInBlock; 101 for (int i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) 102 _curRem += (UInt32)1 << BlockSizeLog; 103 UInt64 rem = Size - _virtPos; 104 if (_curRem > rem) 105 _curRem = (UInt32)rem; 106 } 107 if (size > _curRem) 108 size = _curRem; 109 HRESULT res = Stream->Read(data, size, &size); 110 if (processedSize) 111 *processedSize = size; 112 _physPos += size; 113 _virtPos += size; 114 _curRem -= size; 115 return res; 116 } 117 118 STDMETHODIMP CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 119 { 120 switch (seekOrigin) 121 { 122 case STREAM_SEEK_SET: break; 123 case STREAM_SEEK_CUR: offset += _virtPos; break; 124 case STREAM_SEEK_END: offset += Size; break; 125 default: return STG_E_INVALIDFUNCTION; 126 } 127 if (offset < 0) 128 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 129 if (_virtPos != (UInt64)offset) 130 _curRem = 0; 131 _virtPos = offset; 132 if (newPosition) 133 *newPosition = offset; 134 return S_OK; 135 } 136 137 138 STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize) 139 { 140 if (processedSize) 141 *processedSize = 0; 142 if (_virtPos >= Extents.Back().Virt) 143 return S_OK; 144 if (size == 0) 145 return S_OK; 146 147 unsigned left = 0, right = Extents.Size() - 1; 148 for (;;) 149 { 150 unsigned mid = (left + right) / 2; 151 if (mid == left) 152 break; 153 if (_virtPos < Extents[mid].Virt) 154 right = mid; 155 else 156 left = mid; 157 } 158 159 const CSeekExtent &extent = Extents[left]; 160 UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt); 161 if (_needStartSeek || _phyPos != phyPos) 162 { 163 _needStartSeek = false; 164 _phyPos = phyPos; 165 RINOK(SeekToPhys()); 166 } 167 168 UInt64 rem = Extents[left + 1].Virt - _virtPos; 169 if (size > rem) 170 size = (UInt32)rem; 171 172 HRESULT res = Stream->Read(data, size, &size); 173 _phyPos += size; 174 _virtPos += size; 175 if (processedSize) 176 *processedSize = size; 177 return res; 178 } 179 180 STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 181 { 182 switch (seekOrigin) 183 { 184 case STREAM_SEEK_SET: break; 185 case STREAM_SEEK_CUR: offset += _virtPos; break; 186 case STREAM_SEEK_END: offset += Extents.Back().Virt; break; 187 default: return STG_E_INVALIDFUNCTION; 188 } 189 if (offset < 0) 190 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 191 _virtPos = offset; 192 if (newPosition) 193 *newPosition = _virtPos; 194 return S_OK; 195 } 196 197 198 STDMETHODIMP CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 199 { 200 HRESULT result = S_OK; 201 if (processedSize) 202 *processedSize = 0; 203 if (size > _size) 204 { 205 if (_size == 0) 206 { 207 _overflow = true; 208 if (!_overflowIsAllowed) 209 return E_FAIL; 210 if (processedSize) 211 *processedSize = size; 212 return S_OK; 213 } 214 size = (UInt32)_size; 215 } 216 if (_stream) 217 result = _stream->Write(data, size, &size); 218 _size -= size; 219 if (processedSize) 220 *processedSize = size; 221 return result; 222 } 223 224 225 STDMETHODIMP CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 226 { 227 UInt32 cur; 228 HRESULT res = Stream->Read(data, size, &cur); 229 if (processedSize) 230 *processedSize = cur; 231 _virtPos += cur; 232 return res; 233 } 234 235 STDMETHODIMP CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 236 { 237 switch (seekOrigin) 238 { 239 case STREAM_SEEK_SET: break; 240 case STREAM_SEEK_CUR: offset += _virtPos; break; 241 case STREAM_SEEK_END: 242 { 243 UInt64 pos = 0; 244 RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos)); 245 if (pos < Offset) 246 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 247 _virtPos = pos - Offset; 248 if (newPosition) 249 *newPosition = _virtPos; 250 return S_OK; 251 } 252 default: return STG_E_INVALIDFUNCTION; 253 } 254 if (offset < 0) 255 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 256 _virtPos = offset; 257 if (newPosition) 258 *newPosition = _virtPos; 259 return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL); 260 } 261 262 STDMETHODIMP CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 263 { 264 if (processedSize) 265 *processedSize = 0; 266 if (_virtPos >= _size) 267 { 268 // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. 269 return S_OK; 270 // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF 271 } 272 UInt64 rem = _size - _virtPos; 273 if (rem < size) 274 size = (UInt32)rem; 275 276 UInt64 newPos = _startOffset + _virtPos; 277 UInt64 offsetInCache = newPos - _cachePhyPos; 278 HRESULT res = S_OK; 279 if (newPos >= _cachePhyPos && 280 offsetInCache <= _cacheSize && 281 size <= _cacheSize - (size_t)offsetInCache) 282 memcpy(data, _cache + (size_t)offsetInCache, size); 283 else 284 { 285 if (newPos != _physPos) 286 { 287 _physPos = newPos; 288 RINOK(SeekToPhys()); 289 } 290 res = _stream->Read(data, size, &size); 291 _physPos += size; 292 } 293 if (processedSize) 294 *processedSize = size; 295 _virtPos += size; 296 return res; 297 } 298 299 STDMETHODIMP CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 300 { 301 switch (seekOrigin) 302 { 303 case STREAM_SEEK_SET: break; 304 case STREAM_SEEK_CUR: offset += _virtPos; break; 305 case STREAM_SEEK_END: offset += _size; break; 306 default: return STG_E_INVALIDFUNCTION; 307 } 308 if (offset < 0) 309 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 310 _virtPos = offset; 311 if (newPosition) 312 *newPosition = _virtPos; 313 return S_OK; 314 } 315 316 STDMETHODIMP CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 317 { 318 UInt32 cur; 319 HRESULT res = Stream->Write(data, size, &cur); 320 if (processedSize) 321 *processedSize = cur; 322 _virtPos += cur; 323 if (_virtSize < _virtPos) 324 _virtSize = _virtPos; 325 return res; 326 } 327 328 STDMETHODIMP CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 329 { 330 switch (seekOrigin) 331 { 332 case STREAM_SEEK_SET: break; 333 case STREAM_SEEK_CUR: offset += _virtPos; break; 334 case STREAM_SEEK_END: offset += _virtSize; break; 335 default: return STG_E_INVALIDFUNCTION; 336 } 337 if (offset < 0) 338 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 339 _virtPos = offset; 340 if (newPosition) 341 *newPosition = _virtPos; 342 return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL); 343 } 344 345 STDMETHODIMP CTailOutStream::SetSize(UInt64 newSize) 346 { 347 _virtSize = newSize; 348 return Stream->SetSize(Offset + newSize); 349 } 350