1// LimitedStreams.cpp 2 3#include "StdAfx.h" 4 5#include <string.h> 6 7#include "LimitedStreams.h" 8 9Z7_COM7F_IMF(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 30Z7_COM7F_IMF(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 59Z7_COM7F_IMF(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 = (UInt64)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 = NULL; 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 88Z7_COM7F_IMF(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 (unsigned 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 133Z7_COM7F_IMF(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 = (UInt64)offset; 147 if (newPosition) 148 *newPosition = (UInt64)offset; 149 return S_OK; 150} 151 152 153Z7_COM7F_IMF(CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize)) 154{ 155 if (processedSize) 156 *processedSize = 0; 157 const UInt64 virt = _virtPos; 158 if (virt >= Extents.Back().Virt) 159 return S_OK; 160 if (size == 0) 161 return S_OK; 162 163 unsigned left = _prevExtentIndex; 164 if (virt < Extents[left].Virt || 165 virt >= Extents[left + 1].Virt) 166 { 167 left = 0; 168 unsigned right = Extents.Size() - 1; 169 for (;;) 170 { 171 const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); 172 if (mid == left) 173 break; 174 if (virt < Extents[mid].Virt) 175 right = mid; 176 else 177 left = mid; 178 } 179 _prevExtentIndex = left; 180 } 181 182 { 183 const UInt64 rem = Extents[left + 1].Virt - virt; 184 if (size > rem) 185 size = (UInt32)rem; 186 } 187 188 const CSeekExtent &extent = Extents[left]; 189 190 if (extent.Is_ZeroFill()) 191 { 192 memset(data, 0, size); 193 _virtPos += size; 194 if (processedSize) 195 *processedSize = size; 196 return S_OK; 197 } 198 199 { 200 const UInt64 phy = extent.Phy + (virt - extent.Virt); 201 if (_phyPos != phy) 202 { 203 _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error 204 RINOK(InStream_SeekSet(Stream, phy)) 205 _phyPos = phy; 206 } 207 } 208 209 const HRESULT res = Stream->Read(data, size, &size); 210 _virtPos += size; 211 if (res == S_OK) 212 _phyPos += size; 213 else 214 _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error 215 if (processedSize) 216 *processedSize = size; 217 return res; 218} 219 220 221Z7_COM7F_IMF(CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) 222{ 223 switch (seekOrigin) 224 { 225 case STREAM_SEEK_SET: break; 226 case STREAM_SEEK_CUR: offset += _virtPos; break; 227 case STREAM_SEEK_END: offset += Extents.Back().Virt; break; 228 default: return STG_E_INVALIDFUNCTION; 229 } 230 if (offset < 0) 231 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 232 _virtPos = (UInt64)offset; 233 if (newPosition) 234 *newPosition = _virtPos; 235 return S_OK; 236} 237 238 239Z7_COM7F_IMF(CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) 240{ 241 HRESULT result = S_OK; 242 if (processedSize) 243 *processedSize = 0; 244 if (size > _size) 245 { 246 if (_size == 0) 247 { 248 _overflow = true; 249 if (!_overflowIsAllowed) 250 return E_FAIL; 251 if (processedSize) 252 *processedSize = size; 253 return S_OK; 254 } 255 size = (UInt32)_size; 256 } 257 if (_stream) 258 result = _stream->Write(data, size, &size); 259 _size -= size; 260 if (processedSize) 261 *processedSize = size; 262 return result; 263} 264 265 266Z7_COM7F_IMF(CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) 267{ 268 UInt32 cur; 269 HRESULT res = Stream->Read(data, size, &cur); 270 if (processedSize) 271 *processedSize = cur; 272 _virtPos += cur; 273 return res; 274} 275 276Z7_COM7F_IMF(CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) 277{ 278 switch (seekOrigin) 279 { 280 case STREAM_SEEK_SET: break; 281 case STREAM_SEEK_CUR: offset += _virtPos; break; 282 case STREAM_SEEK_END: 283 { 284 UInt64 pos = 0; 285 RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos)) 286 if (pos < Offset) 287 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 288 _virtPos = pos - Offset; 289 if (newPosition) 290 *newPosition = _virtPos; 291 return S_OK; 292 } 293 default: return STG_E_INVALIDFUNCTION; 294 } 295 if (offset < 0) 296 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 297 _virtPos = (UInt64)offset; 298 if (newPosition) 299 *newPosition = _virtPos; 300 return InStream_SeekSet(Stream, Offset + _virtPos); 301} 302 303Z7_COM7F_IMF(CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) 304{ 305 if (processedSize) 306 *processedSize = 0; 307 if (_virtPos >= _size) 308 { 309 // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. 310 return S_OK; 311 // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF 312 } 313 UInt64 rem = _size - _virtPos; 314 if (rem < size) 315 size = (UInt32)rem; 316 317 UInt64 newPos = _startOffset + _virtPos; 318 UInt64 offsetInCache = newPos - _cachePhyPos; 319 HRESULT res = S_OK; 320 if (newPos >= _cachePhyPos && 321 offsetInCache <= _cacheSize && 322 size <= _cacheSize - (size_t)offsetInCache) 323 { 324 if (size != 0) 325 memcpy(data, _cache + (size_t)offsetInCache, size); 326 } 327 else 328 { 329 if (newPos != _physPos) 330 { 331 _physPos = newPos; 332 RINOK(SeekToPhys()) 333 } 334 res = _stream->Read(data, size, &size); 335 _physPos += size; 336 } 337 if (processedSize) 338 *processedSize = size; 339 _virtPos += size; 340 return res; 341} 342 343Z7_COM7F_IMF(CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) 344{ 345 switch (seekOrigin) 346 { 347 case STREAM_SEEK_SET: break; 348 case STREAM_SEEK_CUR: offset += _virtPos; break; 349 case STREAM_SEEK_END: offset += _size; break; 350 default: return STG_E_INVALIDFUNCTION; 351 } 352 if (offset < 0) 353 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 354 _virtPos = (UInt64)offset; 355 if (newPosition) 356 *newPosition = _virtPos; 357 return S_OK; 358} 359 360Z7_COM7F_IMF(CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) 361{ 362 UInt32 cur; 363 HRESULT res = Stream->Write(data, size, &cur); 364 if (processedSize) 365 *processedSize = cur; 366 _virtPos += cur; 367 if (_virtSize < _virtPos) 368 _virtSize = _virtPos; 369 return res; 370} 371 372Z7_COM7F_IMF(CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) 373{ 374 switch (seekOrigin) 375 { 376 case STREAM_SEEK_SET: break; 377 case STREAM_SEEK_CUR: offset += _virtPos; break; 378 case STREAM_SEEK_END: offset += _virtSize; break; 379 default: return STG_E_INVALIDFUNCTION; 380 } 381 if (offset < 0) 382 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 383 _virtPos = (UInt64)offset; 384 if (newPosition) 385 *newPosition = _virtPos; 386 return Stream->Seek((Int64)(Offset + _virtPos), STREAM_SEEK_SET, NULL); 387} 388 389Z7_COM7F_IMF(CTailOutStream::SetSize(UInt64 newSize)) 390{ 391 _virtSize = newSize; 392 return Stream->SetSize(Offset + newSize); 393} 394