Cinder

  • Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • Examples
  • 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 #include "cinder/Filesystem.h"
00029 
00030 #include <boost/noncopyable.hpp>
00031 
00032 #include <string>
00033 #ifndef __OBJC__
00034 #   include <boost/iostreams/concepts.hpp>
00035 #   include <boost/iostreams/stream.hpp>
00036 #endif
00037 
00038 namespace cinder {
00039 
00040 class StreamBase : private boost::noncopyable {
00041  public:
00042     virtual ~StreamBase() {}
00043     
00044     enum Endianness { STREAM_BIG_ENDIAN, STREAM_LITTLE_ENDIAN };
00045  
00047     static uint8_t      getNativeEndianness()
00048 #ifdef CINDER_LITTLE_ENDIAN
00049         { return STREAM_LITTLE_ENDIAN; }
00050 #else
00051         { return STREAM_BIG_ENDIAN; }
00052 #endif
00053  
00055     const std::string&  getFileName() const { return mFileName; }
00057     void                setFileName( const std::string &aFileName ) { mFileName = aFileName; }
00058 
00060     bool        getDeleteOnDestroy() const { return mDeleteOnDestroy; }
00062     void        setDeleteOnDestroy( bool enable = true ) { mDeleteOnDestroy = enable; }
00063 
00065     virtual off_t       tell() const = 0;
00066 
00068     virtual void        seekAbsolute( off_t absoluteOffset ) = 0;
00069     
00071     virtual void        seekRelative( off_t relativeOffset ) = 0;
00072  
00073  protected:
00074     StreamBase() : mDeleteOnDestroy( false ) {}
00075 
00076     std::string             mFileName;
00077     bool                    mDeleteOnDestroy;
00078 };
00079 
00080 class OStream : public virtual StreamBase {
00081  public:
00082     virtual ~OStream() {}
00083 
00085     void        write( const std::string &s ) { writeData( s.c_str(), s.length() + 1 ); }
00086     void        write( const ci::fs::path &p ) { writeData( p.string().c_str(), p.string().length() + 1 ); }
00087     template<typename T>
00088     void        write( T t ) { IOWrite( &t, sizeof(T) ); }
00089     template<typename T>
00090     void        writeEndian( T t, uint8_t endian ) { if ( endian == STREAM_BIG_ENDIAN ) writeBig( t ); else writeLittle( t ); }
00091     template<typename T>
00092     void        writeBig( T t );
00093     template<typename T>
00094     void        writeLittle( T t );
00095 
00096     void        write( const Buffer &buffer );
00097     void        writeData( const void *src, size_t size );
00098 
00099  protected:
00100     OStream() : StreamBase() {}
00101  
00102     virtual void        IOWrite( const void *t, size_t size ) = 0;
00103 };
00104 
00105 
00106 typedef std::shared_ptr<class OStream>  OStreamRef;
00107 
00108 class IStream : public virtual StreamBase {
00109  public:
00110     virtual ~IStream() {};
00111 
00112     template<typename T>
00113     void        read( T *t ) { IORead( t, sizeof(T) ); }
00114     template<typename T>
00115     void        readEndian( T *t, uint8_t endian ) { if ( endian == STREAM_BIG_ENDIAN ) readBig( t ); else readLittle( t ); }
00116     template<typename T>
00117     void        readBig( T *t );
00118     template<typename T>
00119     void        readLittle( T *t );
00120 
00122     void        read( std::string *s );
00123     void        read( ci::fs::path *p );
00124     void        readFixedString( char *t, size_t maxSize, bool nullTerminate );
00125     void        readFixedString( std::string *t, size_t size );
00126     std::string readLine();
00127     
00128     void            readData( void *dest, size_t size );
00129     virtual size_t  readDataAvailable( void *dest, size_t maxSize ) = 0;
00130 
00131     virtual off_t       size() const = 0;   
00132     virtual bool        isEof() const = 0;
00133 
00134  protected:
00135     IStream() : StreamBase() {}
00136 
00137     virtual void        IORead( void *t, size_t size ) = 0;
00138         
00139     static const int    MINIMUM_BUFFER_SIZE = 8; // minimum bytes of random access a stream must offer relative to the file start
00140 };
00141 typedef std::shared_ptr<IStream>        IStreamRef;
00142 
00143 
00144 class IoStream : public IStream, public OStream {
00145  public:
00146     IoStream() : IStream(), OStream() {}
00147     virtual ~IoStream() {}
00148 };
00149 typedef std::shared_ptr<IoStream>       IoStreamRef;
00150 
00151 
00152 typedef std::shared_ptr<class IStreamFile>  IStreamFileRef;
00153 
00154 class IStreamFile : public IStream {
00155  public:
00157     static IStreamFileRef createRef( FILE *file, bool ownsFile = true, int32_t defaultBufferSize = 2048 );
00158     ~IStreamFile();
00159 
00160     size_t      readDataAvailable( void *dest, size_t maxSize );
00161     
00162     void        seekAbsolute( off_t absoluteOffset );
00163     void        seekRelative( off_t relativeOffset );
00164     off_t       tell() const;
00165     off_t       size() const;
00166     
00167     bool        isEof() const;
00168     
00169     FILE*       getFILE() { return mFile; }
00170 
00171  protected:
00172     IStreamFile( FILE *aFile, bool aOwnsFile = true, int32_t aDefaultBufferSize = 2048 );
00173 
00174     virtual void        IORead( void *t, size_t size );
00175  
00176     FILE                        *mFile;
00177     bool                        mOwnsFile;
00178     size_t                      mBufferSize, mDefaultBufferSize;
00179     std::shared_ptr<uint8_t>    mBuffer;
00180     off_t                       mBufferOffset; // actual offset to do IO from; incremented by IO
00181     off_t                       mBufferFileOffset; // beginning of the buffer in the file
00182     mutable off_t               mSize;
00183     mutable bool                mSizeCached;
00184 };
00185 
00186 
00187 typedef std::shared_ptr<class OStreamFile>  OStreamFileRef;
00188 
00189 class OStreamFile : public OStream {
00190   public:
00192     static OStreamFileRef   createRef( FILE *file, bool ownsFile = true );
00193     ~OStreamFile();
00194 
00195     virtual off_t       tell() const;
00196     virtual void        seekAbsolute( off_t absoluteOffset );
00197     virtual void        seekRelative( off_t relativeOffset );
00198 
00199     FILE*               getFILE() { return mFile; }
00200 
00201     
00202   protected:
00203     OStreamFile( FILE *aFile, bool aOwnsFile = true );
00204 
00205     virtual void        IOWrite( const void *t, size_t size );
00206 
00207     FILE*               mFile;
00208     bool                mOwnsFile;
00209 };
00210 
00211 
00212 typedef std::shared_ptr<class IoStreamFile>     IoStreamFileRef;
00213 
00214 class IoStreamFile : public IoStream {
00215  public:
00217     static IoStreamFileRef createRef( FILE *file, bool ownsFile = true, int32_t defaultBufferSize = 2048 );
00218     ~IoStreamFile();
00219 
00220     size_t      readDataAvailable( void *dest, size_t maxSize );
00221     
00222     void        seekAbsolute( off_t absoluteOffset );
00223     void        seekRelative( off_t relativeOffset );
00224     off_t       tell() const;
00225     off_t       size() const;
00226     
00227     bool        isEof() const;
00228     
00229     FILE*       getFILE() { return mFile; }
00230 
00231  protected:
00232     IoStreamFile( FILE *aFile, bool aOwnsFile = true, int32_t aDefaultBufferSize = 2048 );
00233     
00234     virtual void        IORead( void *t, size_t size );
00235     virtual void        IOWrite( const void *t, size_t size );
00236  
00237     FILE                        *mFile;
00238     bool                        mOwnsFile;
00239     int32_t                     mBufferSize, mDefaultBufferSize;
00240     std::shared_ptr<uint8_t>    mBuffer;
00241     off_t                       mBufferOffset; // actual offset to do IO from; incremented by IO
00242     off_t                       mBufferFileOffset; // beginning of the buffer in the file
00243     mutable off_t               mSize;
00244     mutable bool                mSizeCached;
00245 };
00246 
00247 
00248 typedef std::shared_ptr<class IStreamMem>   IStreamMemRef;
00249 class IStreamMem : public IStream {
00250  public:
00252     static IStreamMemRef        createRef( const void *data, size_t size );
00253     ~IStreamMem();
00254 
00255     size_t      readDataAvailable( void *dest, size_t maxSize );
00256     
00257     void        seekAbsolute( off_t absoluteOffset );
00258     void        seekRelative( off_t relativeOffset );
00260     off_t       tell() const;
00262     off_t       size() const { return static_cast<off_t>( mDataSize ); }
00263 
00265     bool        isEof() const;
00266     
00268     const void* getData() { return reinterpret_cast<const void*>( mData ); }
00269 
00270  protected:
00271     IStreamMem( const void *aData, size_t aDataSize );
00272 
00273     virtual void    IORead( void *t, size_t size );
00274  
00275     const uint8_t   *mData;
00276     size_t          mDataSize;
00277     size_t          mOffset;
00278 };
00279 
00280 
00281 typedef std::shared_ptr<class OStreamMem>       OStreamMemRef;
00282 
00283 class OStreamMem : public OStream {
00284  public:
00285     static OStreamMemRef        createRef( size_t bufferSizeHint = 4096 ) { return std::shared_ptr<OStreamMem>( new OStreamMem( bufferSizeHint ) ); }
00286 
00287     ~OStreamMem();
00288 
00289     virtual off_t       tell() const { return static_cast<off_t>( mOffset ); }
00290     virtual void        seekAbsolute( off_t absoluteOffset );
00291     virtual void        seekRelative( off_t relativeOffset );
00292 
00293     void*               getBuffer() { return mBuffer; }
00294     
00295  protected:
00296     OStreamMem( size_t bufferSizeHint );
00297 
00298     virtual void        IOWrite( const void *t, size_t size );
00299 
00300     void            *mBuffer;
00301     size_t          mDataSize;
00302     size_t          mOffset;
00303 };
00304 
00305 
00306 // This class is a utility to save and restore a stream's state
00307 class IStreamStateRestore {
00308  public:
00309     IStreamStateRestore( IStream &aStream ) : mStream( aStream ), mOffset( aStream.tell() ) {}
00310     ~IStreamStateRestore() {
00311         mStream.seekAbsolute( mOffset );
00312     }
00313     
00314  private:
00315     IStream     &mStream;
00316     off_t       mOffset;
00317 };
00318 
00320 IStreamFileRef  loadFileStream( const std::string &path );
00322 OStreamFileRef  writeFileStream( const std::string &path, bool createParents = true );
00324 IoStreamFileRef readWriteFileStream( const std::string &path );
00325 
00327 void loadStreamMemory( IStreamRef is, std::shared_ptr<uint8_t> *resultData, size_t *resultDataSize );
00329 Buffer loadStreamBuffer( IStreamRef is );
00330 
00331 
00332 // Stream exception
00333 class StreamExc : public Exception {
00334 };
00335 
00336 class StreamExcOutOfMemory : public StreamExc {
00337 };
00338 
00339 #ifndef __OBJC__
00340 class cinder_stream_source {
00341  public:
00342     typedef char char_type;
00343     typedef boost::iostreams::source_tag category;
00344 
00345     cinder_stream_source( cinder::IStreamRef aStream ) : mStream( aStream ) {}
00346 
00347     std::streamsize read( char *s, std::streamsize n )
00348     {
00349         if( mStream->isEof() )
00350             return -1;
00351         
00352         return (std::streamsize)mStream->readDataAvailable( s, (size_t)n );
00353     }
00354 
00355  protected:
00356     IStreamRef      mStream; // a little kludgy but this is for convenience
00357 };
00358 
00359 typedef boost::iostreams::stream<cinder_stream_source> cinder_istream;
00360 
00361 class cinder_stream_sink {
00362  public:
00363     typedef char char_type;
00364     typedef boost::iostreams::sink_tag category;
00365 
00366     cinder_stream_sink( OStreamRef aStream ) : mStream( aStream ) {}
00367 
00368     std::streamsize write( const char *s, std::streamsize n )
00369     {
00370         mStream->writeData( s, (size_t)n );
00371         return n;
00372     }
00373 
00374  protected:
00375     OStreamRef      mStream;
00376 };
00377 
00378 typedef boost::iostreams::stream<cinder_stream_sink> cinder_ostream;
00379 
00380 class cinder_stream_bidirectional_device {
00381  public:
00382     typedef char char_type;
00383     typedef boost::iostreams::seekable_device_tag category;
00384 
00385     cinder_stream_bidirectional_device( cinder::IoStreamRef aStream ) : mStream( aStream ) {}
00386 
00387     std::streamsize read( char *s, std::streamsize n )
00388     {
00389         return static_cast<std::streamsize>( mStream->readDataAvailable( s, (size_t)n ) );
00390     }
00391 
00392     std::streamsize write( const char *s, std::streamsize n )
00393     {
00394         mStream->writeData( s, (size_t)n );
00395         return n;
00396     }
00397 
00398     boost::iostreams::stream_offset seek( boost::iostreams::stream_offset off, std::ios_base::seekdir way)
00399     {
00400         if( way == std::ios_base::beg ) {
00401             mStream->seekAbsolute( (off_t)off );
00402         }
00403         else if( way == std::ios_base::cur ) {
00404             mStream->seekRelative( (off_t)off );
00405         }
00406         else { // way == std::ios_base::end
00407             mStream->seekAbsolute( -(off_t)off );
00408         }
00409         return mStream->tell();
00410     }
00411 
00412  protected:
00413     IoStreamRef     mStream;
00414 };
00415 
00416 typedef boost::iostreams::stream<cinder_stream_bidirectional_device> cinder_iostream;
00417 
00418 #endif // ! __OBJC__
00419 
00420 } // namespace cinder