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