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 != NULL) 21 *processedSize = realProcessedSize; 22 return result; 23 } 24 25 STDMETHODIMP CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 26 { 27 if (processedSize != NULL) 28 *processedSize = 0; 29 if (_virtPos >= _size) 30 return (_virtPos == _size) ? S_OK: E_FAIL; 31 UInt64 rem = _size - _virtPos; 32 if (rem < size) 33 size = (UInt32)rem; 34 UInt64 newPos = _startOffset + _virtPos; 35 if (newPos != _physPos) 36 { 37 _physPos = newPos; 38 RINOK(SeekToPhys()); 39 } 40 HRESULT res = _stream->Read(data, size, &size); 41 if (processedSize != NULL) 42 *processedSize = size; 43 _physPos += size; 44 _virtPos += size; 45 return res; 46 } 47 48 STDMETHODIMP CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 49 { 50 switch(seekOrigin) 51 { 52 case STREAM_SEEK_SET: _virtPos = offset; break; 53 case STREAM_SEEK_CUR: _virtPos += offset; break; 54 case STREAM_SEEK_END: _virtPos = _size + offset; break; 55 default: return STG_E_INVALIDFUNCTION; 56 } 57 if (newPosition) 58 *newPosition = _virtPos; 59 return S_OK; 60 } 61 62 STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 63 { 64 if (processedSize != NULL) 65 *processedSize = 0; 66 if (_virtPos >= Size) 67 return (_virtPos == Size) ? S_OK: E_FAIL; 68 69 if (_curRem == 0) 70 { 71 UInt32 blockSize = (UInt32)1 << BlockSizeLog; 72 UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog); 73 UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); 74 UInt32 phyBlock = Vector[virtBlock]; 75 UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock; 76 if (newPos != _physPos) 77 { 78 _physPos = newPos; 79 RINOK(SeekToPhys()); 80 } 81 _curRem = blockSize - offsetInBlock; 82 for (int i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) 83 _curRem += (UInt32)1 << BlockSizeLog; 84 UInt64 rem = Size - _virtPos; 85 if (_curRem > rem) 86 _curRem = (UInt32)rem; 87 } 88 if (size > _curRem) 89 size = _curRem; 90 HRESULT res = Stream->Read(data, size, &size); 91 if (processedSize != NULL) 92 *processedSize = size; 93 _physPos += size; 94 _virtPos += size; 95 _curRem -= size; 96 return res; 97 } 98 99 STDMETHODIMP CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 100 { 101 UInt64 newVirtPos = offset; 102 switch(seekOrigin) 103 { 104 case STREAM_SEEK_SET: break; 105 case STREAM_SEEK_CUR: newVirtPos += _virtPos; break; 106 case STREAM_SEEK_END: newVirtPos += Size; break; 107 default: return STG_E_INVALIDFUNCTION; 108 } 109 if (_virtPos != newVirtPos) 110 _curRem = 0; 111 _virtPos = newVirtPos; 112 if (newPosition) 113 *newPosition = newVirtPos; 114 return S_OK; 115 } 116 117 118 HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream) 119 { 120 *resStream = 0; 121 CLimitedInStream *streamSpec = new CLimitedInStream; 122 CMyComPtr<ISequentialInStream> streamTemp = streamSpec; 123 streamSpec->SetStream(inStream); 124 RINOK(streamSpec->InitAndSeek(pos, size)); 125 streamSpec->SeekToStart(); 126 *resStream = streamTemp.Detach(); 127 return S_OK; 128 } 129 130 STDMETHODIMP CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 131 { 132 HRESULT result = S_OK; 133 if (processedSize != NULL) 134 *processedSize = 0; 135 if (size > _size) 136 { 137 if (_size == 0) 138 { 139 _overflow = true; 140 if (!_overflowIsAllowed) 141 return E_FAIL; 142 if (processedSize != NULL) 143 *processedSize = size; 144 return S_OK; 145 } 146 size = (UInt32)_size; 147 } 148 if (_stream) 149 result = _stream->Write(data, size, &size); 150 _size -= size; 151 if (processedSize != NULL) 152 *processedSize = size; 153 return result; 154 } 155