Ticket #8581: substreams.diff

File substreams.diff, 6.0 KB (added by SF/madm00se, 14 years ago)

SubStreams Patch v1

  • common/stream.h

     
    210210 * @todo We really need better error handling here!
    211211 *       Like seek should somehow indicate whether it failed.
    212212 */
    213 class SeekableReadStream : public ReadStream {
     213class SeekableReadStream : virtual public ReadStream {
    214214public:
    215215
    216216        virtual uint32 pos() const = 0;
    217217        virtual uint32 size() const = 0;
    218218
    219219        virtual void seek(int32 offset, int whence = SEEK_SET) = 0;
    220        
     220
    221221        void skip(uint32 offset) { seek(offset, SEEK_CUR); }
    222222
    223223        /**
     
    233233        virtual char *readLine(char *buf, size_t bufSize);
    234234};
    235235
     236/**
     237 * SubReadStream provides access to a ReadStream restricted to the range
     238 * [currentPosition, currentPosition+end).
     239 * Manipulating the parent stream directly /will/ mess up a substream.
     240 * Likewise, manipulating two substreams of a parent stream will cause them to
     241 * step on each others toes.
     242 */
     243class SubReadStream : virtual public ReadStream {
     244protected:
     245        ReadStream *_parentStream;
     246        uint32 _pos;
     247        uint32 _end;
     248public:
     249        SubReadStream(ReadStream *parentStream, uint32 end)
     250                : _parentStream(parentStream), _pos(0), _end(end) {}
    236251
     252        virtual bool eos() const { return _pos == _end; }
     253        virtual uint32 read(void *dataPtr, uint32 dataSize);
     254};
     255
     256/*
     257 * SeekableSubReadStream provides access to a SeekableReadStream restricted to
     258 * the range [begin, end).
     259 * The same caveats apply to SeekableSubReadStream as do to SeekableReadStream.
     260 */
     261class SeekableSubReadStream : public SubReadStream, public SeekableReadStream {
     262protected:
     263        SeekableReadStream *_parentStream;
     264        uint32 _begin;
     265public:
     266        SeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end);
     267
     268        virtual uint32 pos() const { return _pos - _begin; }
     269        virtual uint32 size() const { return _end - _begin; }
     270
     271        virtual void seek(int32 offset, int whence = SEEK_SET);
     272};
     273
    237274/**
    238275 * XORReadStream is a wrapper around an arbitrary other ReadStream,
    239276 * which 'decrypts' the data being read by XORing all data bytes with the given
  • common/stream.cpp

     
    105105
    106106                c = readByte();
    107107        }
    108        
     108
    109109        // This should fix a bug while using readLine with Common::File
    110110        // it seems that it sets the eos flag after an invalid read
    111111        // and at the same time the ioFailed flag
     
    118118        return buf;
    119119}
    120120
     121uint32 SubReadStream::read(void *dataPtr, uint32 dataSize)
     122{
     123        dataSize = MIN(dataSize, _end - _pos);
    121124
     125        dataSize = _parentStream->read(dataPtr, dataSize);
     126        _pos += dataSize;
     127
     128        return dataSize;
     129}
     130
     131SeekableSubReadStream::SeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end)
     132        : SubReadStream(parentStream, end), _parentStream(parentStream), _begin(begin)
     133{
     134        assert(_begin <= _end);
     135        _pos = _begin;
     136        _parentStream->seek(_pos);
     137}
     138
     139void SeekableSubReadStream::seek(int32 offset, int whence)
     140{
     141        assert(_pos >= _begin);
     142        assert(_pos <= _end);
     143
     144        switch(whence)
     145        {
     146        case SEEK_END:
     147                offset = size() - offset;
     148                // fallthrough
     149        case SEEK_SET:
     150                _pos = _begin + offset;
     151                break;
     152        case SEEK_CUR:
     153                _pos += offset;
     154        }
     155
     156        assert(_pos >= _begin);
     157        assert(_pos <= _end);
     158
     159        _parentStream->seek(_pos);
     160}
     161
    122162}       // End of namespace Common
  • test/common/seekablesubreadstream.h

     
     1#include <cxxtest/TestSuite.h>
     2
     3#include "common/stdafx.h"
     4#include "common/stream.h"
     5
     6class SeekableSubReadStreamTestSuite : public CxxTest::TestSuite
     7{
     8        public:
     9        void test_traverse( void )
     10        {
     11                byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
     12                Common::MemoryReadStream ms = Common::MemoryReadStream(contents, 10);
     13
     14                int start = 2, end = 8;
     15
     16                Common::SeekableSubReadStream ssrs = Common::SeekableSubReadStream(&ms, start, end);
     17
     18                int i;
     19                byte b;
     20                for (i = start; i < end; ++i)
     21                {
     22                        TS_ASSERT( !ssrs.eos() );
     23
     24                        TS_ASSERT_EQUALS( i - start, ssrs.pos() );
     25
     26                        ssrs.read(&b, 1);
     27                        TS_ASSERT_EQUALS( i, b );
     28                }
     29
     30                TS_ASSERT( ssrs.eos() );
     31        }
     32
     33        void test_seek( void )
     34        {
     35                byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
     36                Common::MemoryReadStream ms = Common::MemoryReadStream(contents, 10);
     37
     38                Common::SeekableSubReadStream ssrs = Common::SeekableSubReadStream(&ms, 1, 9);
     39                byte b;
     40
     41                TS_ASSERT_EQUALS( ssrs.pos(), 0 );
     42
     43                ssrs.seek(1, SEEK_SET);
     44                TS_ASSERT_EQUALS( ssrs.pos(), 1 );
     45                b = ssrs.readByte();
     46                TS_ASSERT_EQUALS( b, 2 );
     47
     48                ssrs.seek(5, SEEK_CUR);
     49                TS_ASSERT_EQUALS( ssrs.pos(), 7 );
     50                b = ssrs.readByte();
     51                TS_ASSERT_EQUALS( b, 8 );
     52
     53                ssrs.seek(-3, SEEK_CUR);
     54                TS_ASSERT_EQUALS( ssrs.pos(), 5 );
     55                b = ssrs.readByte();
     56                TS_ASSERT_EQUALS( b, 6 );
     57
     58                ssrs.seek(0, SEEK_END);
     59                TS_ASSERT_EQUALS( ssrs.pos(), 8 );
     60                TS_ASSERT( ssrs.eos() );
     61
     62                ssrs.seek(3, SEEK_END);
     63                TS_ASSERT_EQUALS( ssrs.pos(), 5 );
     64                b = ssrs.readByte();
     65                TS_ASSERT_EQUALS( b, 6 );
     66
     67                ssrs.seek(8, SEEK_END);
     68                TS_ASSERT_EQUALS( ssrs.pos(), 0 );
     69                b = ssrs.readByte();
     70                TS_ASSERT_EQUALS( b, 1 );
     71        }
     72};
  • test/common/subreadstream.h

     
     1#include <cxxtest/TestSuite.h>
     2
     3#include "common/stdafx.h"
     4#include "common/stream.h"
     5
     6class SubReadStreamTestSuite : public CxxTest::TestSuite
     7{
     8        public:
     9        void test_traverse( void )
     10        {
     11                byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
     12                Common::MemoryReadStream ms = Common::MemoryReadStream(contents, 10);
     13
     14                int end = 5;
     15
     16                Common::SubReadStream srs = Common::SubReadStream(&ms, end);
     17
     18                int i;
     19                byte b;
     20                for (i = 0; i < end; ++i)
     21                {
     22                        TS_ASSERT( !srs.eos() );
     23
     24                        srs.read(&b, 1);
     25                        TS_ASSERT_EQUALS( i, b );
     26                }
     27
     28                TS_ASSERT( srs.eos() );
     29        }
     30};