Home | History | Annotate | Download | only in Common
      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