Cinder

  • Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

include/cinder/Stream.h

Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2010, The Barbarian Group
00003  All rights reserved.
00004 
00005  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00006  the following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00009     the following disclaimer.
00010     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00011     the following disclaimer in the documentation and/or other materials provided with the distribution.
00012 
00013  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00014  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00015  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00016  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00017  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00018  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00019  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00020  POSSIBILITY OF SUCH DAMAGE.
00021 */
00022 
00023 #pragma once 
00024 
00025 #include "cinder/Cinder.h"
00026 #include "cinder/Buffer.h"
00027 #include "cinder/Exception.h"
00028 
00029 #include <boost/noncopyable.hpp>
00030 
00031 #include <string>
00032 #ifndef __OBJC__
00033 #   include <boost/iostreams/concepts.hpp>
00034 #   include <boost/iostreams/stream.hpp>
00035 #endif
00036 
00037 namespace cinder {
00038 
00039 class StreamBase : private boost::noncopyable {
00040  public:
00041     virtual ~StreamBase() {}
00042     
00043     enum Endianness { STREAM_BIG_ENDIAN, STREAM_LITTLE_ENDIAN };
00044  
00046     static uint8_t      getNativeEndianness()
00047 #ifdef CINDER_LITTLE_ENDIAN
00048         { return STREAM_LITTLE_ENDIAN; }
00049 #else
00050         { return STREAM_BIG_ENDIAN; }
00051 #endif
00052  
00054     const std::string&  getFileName() const { return mFileName; }
00056     void                setFileName( const std::string &aFileName ) { mFileName = aFileName; }
00057 
00059     bool        getDeleteOnDestroy() const { return mDeleteOnDestroy; }
00061     void        setDeleteOnDestroy( bool enable = true ) { mDeleteOnDestroy = enable; }
00062 
00064     virtual off_t       tell() const = 0;
00065 
00067     virtual void        seekAbsolute( off_t absoluteOffset ) = 0;
00068     
00070     virtual void        seekRelative( off_t relativeOffset ) = 0;
00071  
00072  protected:
00073     StreamBase() : mDeleteOnDestroy( false ) {}
00074 
00075     std::string             mFileName;
00076     bool                    mDeleteOnDestroy;
00077 };
00078 
00079 class OStream : public virtual StreamBase {
00080  public:
00081     virtual ~OStream() {}
00082 
00083     template<typename T>
00084     void        write( T t );
00085     template<typename T>
00086     void        writeEndian( T t, uint8_t endian ) { if ( endian == STREAM_BIG_ENDIAN ) writeBig( t ); else writeLittle( t ); }
00087     template<typename T>
00088     void        writeBig( T t );
00089     template<typename T>
00090     void        writeLittle( T t );
00091 
00092     void        write( const Buffer &buffer );
00093     void        writeData( const void *src, size_t size );
00094 
00095  protected:
00096     OStream() : StreamBase() {}
00097  
00098     virtual void        IOWrite( const void *t, size_t size ) = 0;
00099 };
00100 
00101 
00102 typedef shared_ptr<class OStream>   OStreamRef;
00103 
00104 class IStream : public virtual StreamBase {
00105  public:
00106     virtual ~IStream() {};
00107 
00108     template<typename T>
00109     void        read( T *t );
00110     template<typename T>
00111     void        readEndian( T *t, uint8_t endian ) { if ( endian == STREAM_BIG_ENDIAN ) readBig( t ); else readLittle( t ); }
00112     template<typename T>
00113     void        readBig( T *t );
00114     template<typename T>
00115     void        readLittle( T *t );
00116     
00117     void        readFixedString( char *t, size_t maxSize, bool nullTerminate );
00118     void        readFixedString( std::string *t, size_t size );
00119     std::string readLine();
00120     
00121     void            readData( void *dest, size_t size );
00122     virtual size_t  readDataAvailable( void *dest, size_t maxSize ) = 0;
00123 
00124     virtual off_t       size() const = 0;   
00125     virtual bool        isEof() const = 0;
00126 
00127  protected:
00128     IStream() : StreamBase() {}
00129 
00130     virtual void        IORead( void *t, size_t size ) = 0;
00131         
00132     static const int    MINIMUM_BUFFER_SIZE = 8; // minimum bytes of random access a stream must offer relative to the file start
00133 };
00134 typedef shared_ptr<IStream>     IStreamRef;
00135 
00136 
00137 class IoStream : public IStream, public OStream {
00138  public:
00139     IoStream() : IStream(), OStream() {}
00140     virtual ~IoStream() {}
00141 };
00142 typedef shared_ptr<IoStream>        IoStreamRef;
00143 
00144 
00145 typedef shared_ptr<class IStreamFile>   IStreamFileRef;
00146 
00147 class IStreamFile : public IStream {
00148  public:
00150     static IStreamFileRef createRef( FILE *file, bool ownsFile = true, int32_t defaultBufferSize = 2048 );
00151     ~IStreamFile();
00152 
00153     size_t      readDataAvailable( void *dest, size_t maxSize );
00154     
00155     void        seekAbsolute( off_t absoluteOffset );
00156     void        seekRelative( off_t relativeOffset );
00157     off_t       tell() const;
00158     off_t       size() const;
00159     
00160     bool        isEof() const;
00161     
00162     FILE*       getFILE() { return mFile; }
00163 
00164  protected:
00165     IStreamFile( FILE *aFile, bool aOwnsFile = true, int32_t aDefaultBufferSize = 2048 );
00166 
00167     virtual void        IORead( void *t, size_t size );
00168  
00169     FILE                    *mFile;
00170     bool                    mOwnsFile;
00171     size_t                  mBufferSize, mDefaultBufferSize;
00172     shared_ptr<uint8_t> mBuffer;
00173     off_t                   mBufferOffset; // actual offset to do IO from; incremented by IO
00174     off_t                   mBufferFileOffset; // beginning of the buffer in the file
00175     mutable off_t           mSize;
00176     mutable bool            mSizeCached;
00177 };
00178 
00179 
00180 typedef shared_ptr<class OStreamFile>   OStreamFileRef;
00181 
00182 class OStreamFile : public OStream {
00183   public:
00185     static OStreamFileRef   createRef( FILE *file, bool ownsFile = true );
00186     ~OStreamFile();
00187 
00188     virtual off_t       tell() const;
00189     virtual void        seekAbsolute( off_t absoluteOffset );
00190     virtual void        seekRelative( off_t relativeOffset );
00191 
00192     FILE*               getFILE() { return mFile; }
00193 
00194     
00195   protected:
00196     OStreamFile( FILE *aFile, bool aOwnsFile = true );
00197 
00198     virtual void        IOWrite( const void *t, size_t size );
00199 
00200     FILE*               mFile;
00201     bool                mOwnsFile;
00202 };
00203 
00204 
00205 typedef shared_ptr<class IoStreamFile>      IoStreamFileRef;
00206 
00207 class IoStreamFile : public IoStream {
00208  public:
00210     static IoStreamFileRef createRef( FILE *file, bool ownsFile = true, int32_t defaultBufferSize = 2048 );
00211     ~IoStreamFile();
00212 
00213     size_t      readDataAvailable( void *dest, size_t maxSize );
00214     
00215     void        seekAbsolute( off_t absoluteOffset );
00216     void        seekRelative( off_t relativeOffset );
00217     off_t       tell() const;
00218     off_t       size() const;
00219     
00220     bool        isEof() const;
00221     
00222     FILE*       getFILE() { return mFile; }
00223 
00224  protected:
00225     IoStreamFile( FILE *aFile, bool aOwnsFile = true, int32_t aDefaultBufferSize = 2048 );
00226     
00227     virtual void        IORead( void *t, size_t size );
00228     virtual void        IOWrite( const void *t, size_t size );
00229  
00230     FILE                    *mFile;
00231     bool                    mOwnsFile;
00232     int32_t                 mBufferSize, mDefaultBufferSize;
00233     shared_ptr<uint8_t>     mBuffer;
00234     off_t                   mBufferOffset; // actual offset to do IO from; incremented by IO
00235     off_t                   mBufferFileOffset; // beginning of the buffer in the file
00236     mutable off_t           mSize;
00237     mutable bool            mSizeCached;
00238 };
00239 
00240 
00241 typedef shared_ptr<class IStreamMem>    IStreamMemRef;
00242 class IStreamMem : public IStream {
00243  public:
00245     static IStreamMemRef        createRef( const void *data, size_t size );
00246     ~IStreamMem();
00247 
00248     size_t      readDataAvailable( void *dest, size_t maxSize );
00249     
00250     void        seekAbsolute( off_t absoluteOffset );
00251     void        seekRelative( off_t relativeOffset );
00253     off_t       tell() const;
00255     off_t       size() const { return static_cast<off_t>( mDataSize ); }
00256 
00258     bool        isEof() const;
00259     
00261     const void* getData() { return reinterpret_cast<const void*>( mData ); }
00262 
00263  protected:
00264     IStreamMem( const void *aData, size_t aDataSize );
00265 
00266     virtual void    IORead( void *t, size_t size );
00267  
00268     const uint8_t   *mData;
00269     size_t          mDataSize;
00270     size_t          mOffset;
00271 };
00272 
00273 
00274 class OStreamMem : public OStream {
00275  public:
00276     ~OStreamMem();
00277 
00278     virtual off_t       tell() const { return static_cast<off_t>( mOffset ); }
00279     virtual void        seekAbsolute( off_t absoluteOffset );
00280     virtual void        seekRelative( off_t relativeOffset );
00281 
00282     void*               getBuffer() { return mBuffer; }
00283     
00284  protected:
00285     OStreamMem( size_t bufferSizeHint );
00286 
00287     virtual void        IOWrite( const void *t, size_t size );
00288 
00289     void            *mBuffer;
00290     size_t          mDataSize;
00291     size_t          mOffset;
00292 };
00293 
00294 typedef shared_ptr<OStreamMem>      OStreamMemRef;
00295 
00296 
00297 // This class is a utility to save and restore a stream's state
00298 class IStreamStateRestore {
00299  public:
00300     IStreamStateRestore( IStream &aStream ) : mStream( aStream ), mOffset( aStream.tell() ) {}
00301     ~IStreamStateRestore() {
00302         mStream.seekAbsolute( mOffset );
00303     }
00304     
00305  private:
00306     IStream     &mStream;
00307     off_t       mOffset;
00308 };
00309 
00311 IStreamFileRef  loadFileStream( const std::string &path );
00313 OStreamFileRef  writeFileStream( const std::string &path, bool createParents = true );
00315 IoStreamFileRef readWriteFileStream( const std::string &path );
00316 
00318 void loadStreamMemory( IStreamRef is, shared_ptr<uint8_t> *resultData, size_t *resultDataSize );
00320 Buffer loadStreamBuffer( IStreamRef is );
00321 
00322 
00323 // Stream exception
00324 class StreamExc : public Exception {
00325 };
00326 
00327 class StreamExcOutOfMemory : public StreamExc {
00328 };
00329 
00330 #ifndef __OBJC__
00331 class cinder_stream_source {
00332  public:
00333     typedef char char_type;
00334     typedef boost::iostreams::source_tag category;
00335 
00336     cinder_stream_source( cinder::IStreamRef aStream ) : mStream( aStream ) {}
00337 
00338     std::streamsize read( char *s, std::streamsize n )
00339     {
00340         if( mStream->isEof() )
00341             return -1;
00342         
00343         return (std::streamsize)mStream->readDataAvailable( s, (size_t)n );
00344     }
00345 
00346  protected:
00347     IStreamRef      mStream; // a little kludgy but this is for convenience
00348 };
00349 
00350 typedef boost::iostreams::stream<cinder_stream_source> cinder_istream;
00351 
00352 class cinder_stream_sink {
00353  public:
00354     typedef char char_type;
00355     typedef boost::iostreams::sink_tag category;
00356 
00357     cinder_stream_sink( OStreamRef aStream ) : mStream( aStream ) {}
00358 
00359     std::streamsize write( const char *s, std::streamsize n )
00360     {
00361         mStream->writeData( s, (size_t)n );
00362         return n;
00363     }
00364 
00365  protected:
00366     OStreamRef      mStream;
00367 };
00368 
00369 typedef boost::iostreams::stream<cinder_stream_sink> cinder_ostream;
00370 
00371 class cinder_stream_bidirectional_device {
00372  public:
00373     typedef char char_type;
00374     typedef boost::iostreams::seekable_device_tag category;
00375 
00376     cinder_stream_bidirectional_device( cinder::IoStreamRef aStream ) : mStream( aStream ) {}
00377 
00378     std::streamsize read( char *s, std::streamsize n )
00379     {
00380         return static_cast<std::streamsize>( mStream->readDataAvailable( s, (size_t)n ) );
00381     }
00382 
00383     std::streamsize write( const char *s, std::streamsize n )
00384     {
00385         mStream->writeData( s, (size_t)n );
00386         return n;
00387     }
00388 
00389     boost::iostreams::stream_offset seek( boost::iostreams::stream_offset off, std::ios_base::seekdir way)
00390     {
00391         if( way == std::ios_base::beg ) {
00392             mStream->seekAbsolute( (off_t)off );
00393         }
00394         else if( way == std::ios_base::cur ) {
00395             mStream->seekRelative( (off_t)off );
00396         }
00397         else { // way == std::ios_base::end
00398             mStream->seekAbsolute( -(off_t)off );
00399         }
00400         return mStream->tell();
00401     }
00402 
00403  protected:
00404     IoStreamRef     mStream;
00405 };
00406 
00407 typedef boost::iostreams::stream<cinder_stream_bidirectional_device> cinder_iostream;
00408 
00409 #endif // ! __OBJC__
00410 
00411 } // namespace cinder