00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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 fs::path& getFileName() const { return mFileName; }
00057 void setFileName( const fs::path &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 fs::path 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;
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 create( 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 size_t readDataImpl( void *dest, size_t maxSize );
00176
00177 FILE *mFile;
00178 bool mOwnsFile;
00179 size_t mBufferSize, mDefaultBufferSize;
00180 std::shared_ptr<uint8_t> mBuffer;
00181 off_t mBufferOffset;
00182 off_t mBufferFileOffset;
00183 mutable off_t mSize;
00184 mutable bool mSizeCached;
00185 };
00186
00187
00188 typedef std::shared_ptr<class OStreamFile> OStreamFileRef;
00189
00190 class OStreamFile : public OStream {
00191 public:
00193 static OStreamFileRef create( FILE *file, bool ownsFile = true );
00194 ~OStreamFile();
00195
00196 virtual off_t tell() const;
00197 virtual void seekAbsolute( off_t absoluteOffset );
00198 virtual void seekRelative( off_t relativeOffset );
00199
00200 FILE* getFILE() { return mFile; }
00201
00202
00203 protected:
00204 OStreamFile( FILE *aFile, bool aOwnsFile = true );
00205
00206 virtual void IOWrite( const void *t, size_t size );
00207
00208 FILE* mFile;
00209 bool mOwnsFile;
00210 };
00211
00212
00213 typedef std::shared_ptr<class IoStreamFile> IoStreamFileRef;
00214
00215 class IoStreamFile : public IoStream {
00216 public:
00218 static IoStreamFileRef create( FILE *file, bool ownsFile = true, int32_t defaultBufferSize = 2048 );
00219 ~IoStreamFile();
00220
00221 size_t readDataAvailable( void *dest, size_t maxSize );
00222
00223 void seekAbsolute( off_t absoluteOffset );
00224 void seekRelative( off_t relativeOffset );
00225 off_t tell() const;
00226 off_t size() const;
00227
00228 bool isEof() const;
00229
00230 FILE* getFILE() { return mFile; }
00231
00232 protected:
00233 IoStreamFile( FILE *aFile, bool aOwnsFile = true, int32_t aDefaultBufferSize = 2048 );
00234
00235 virtual void IORead( void *t, size_t size );
00236 size_t readDataImpl( void *dest, size_t maxSize );
00237 virtual void IOWrite( const void *t, size_t size );
00238
00239 FILE *mFile;
00240 bool mOwnsFile;
00241 int32_t mBufferSize, mDefaultBufferSize;
00242 std::shared_ptr<uint8_t> mBuffer;
00243 off_t mBufferOffset;
00244 off_t mBufferFileOffset;
00245 mutable off_t mSize;
00246 mutable bool mSizeCached;
00247 };
00248
00249
00250 typedef std::shared_ptr<class IStreamMem> IStreamMemRef;
00251 class IStreamMem : public IStream {
00252 public:
00254 static IStreamMemRef create( const void *data, size_t size );
00255 ~IStreamMem();
00256
00257 size_t readDataAvailable( void *dest, size_t maxSize );
00258
00259 void seekAbsolute( off_t absoluteOffset );
00260 void seekRelative( off_t relativeOffset );
00262 off_t tell() const;
00264 off_t size() const { return static_cast<off_t>( mDataSize ); }
00265
00267 bool isEof() const;
00268
00270 const void* getData() { return reinterpret_cast<const void*>( mData ); }
00271
00272 protected:
00273 IStreamMem( const void *aData, size_t aDataSize );
00274
00275 virtual void IORead( void *t, size_t size );
00276
00277 const uint8_t *mData;
00278 size_t mDataSize;
00279 size_t mOffset;
00280 };
00281
00282
00283 typedef std::shared_ptr<class OStreamMem> OStreamMemRef;
00284
00285 class OStreamMem : public OStream {
00286 public:
00287 static OStreamMemRef create( size_t bufferSizeHint = 4096 ) { return std::shared_ptr<OStreamMem>( new OStreamMem( bufferSizeHint ) ); }
00288
00289 ~OStreamMem();
00290
00291 virtual off_t tell() const { return static_cast<off_t>( mOffset ); }
00292 virtual void seekAbsolute( off_t absoluteOffset );
00293 virtual void seekRelative( off_t relativeOffset );
00294
00295 void* getBuffer() { return mBuffer; }
00296
00297 protected:
00298 OStreamMem( size_t bufferSizeHint );
00299
00300 virtual void IOWrite( const void *t, size_t size );
00301
00302 void *mBuffer;
00303 size_t mDataSize;
00304 size_t mOffset;
00305 };
00306
00307
00308
00309 class IStreamStateRestore {
00310 public:
00311 IStreamStateRestore( IStream &aStream ) : mStream( aStream ), mOffset( aStream.tell() ) {}
00312 ~IStreamStateRestore() {
00313 mStream.seekAbsolute( mOffset );
00314 }
00315
00316 private:
00317 IStream &mStream;
00318 off_t mOffset;
00319 };
00320
00322 IStreamFileRef loadFileStream( const fs::path &path );
00324 OStreamFileRef writeFileStream( const fs::path &path, bool createParents = true );
00326 IoStreamFileRef readWriteFileStream( const fs::path &path );
00327
00329 void loadStreamMemory( IStreamRef is, std::shared_ptr<uint8_t> *resultData, size_t *resultDataSize );
00331 Buffer loadStreamBuffer( IStreamRef is );
00332
00333
00334
00335 class StreamExc : public Exception {
00336 };
00337
00338 class StreamExcOutOfMemory : public StreamExc {
00339 };
00340
00341 #ifndef __OBJC__
00342 class cinder_stream_source {
00343 public:
00344 typedef char char_type;
00345 typedef boost::iostreams::source_tag category;
00346
00347 cinder_stream_source( cinder::IStreamRef aStream ) : mStream( aStream ) {}
00348
00349 std::streamsize read( char *s, std::streamsize n )
00350 {
00351 if( mStream->isEof() )
00352 return -1;
00353
00354 return (std::streamsize)mStream->readDataAvailable( s, (size_t)n );
00355 }
00356
00357 protected:
00358 IStreamRef mStream;
00359 };
00360
00361 typedef boost::iostreams::stream<cinder_stream_source> cinder_istream;
00362
00363 class cinder_stream_sink {
00364 public:
00365 typedef char char_type;
00366 typedef boost::iostreams::sink_tag category;
00367
00368 cinder_stream_sink( OStreamRef aStream ) : mStream( aStream ) {}
00369
00370 std::streamsize write( const char *s, std::streamsize n )
00371 {
00372 mStream->writeData( s, (size_t)n );
00373 return n;
00374 }
00375
00376 protected:
00377 OStreamRef mStream;
00378 };
00379
00380 typedef boost::iostreams::stream<cinder_stream_sink> cinder_ostream;
00381
00382 class cinder_stream_bidirectional_device {
00383 public:
00384 typedef char char_type;
00385 typedef boost::iostreams::seekable_device_tag category;
00386
00387 cinder_stream_bidirectional_device( cinder::IoStreamRef aStream ) : mStream( aStream ) {}
00388
00389 std::streamsize read( char *s, std::streamsize n )
00390 {
00391 return static_cast<std::streamsize>( mStream->readDataAvailable( s, (size_t)n ) );
00392 }
00393
00394 std::streamsize write( const char *s, std::streamsize n )
00395 {
00396 mStream->writeData( s, (size_t)n );
00397 return n;
00398 }
00399
00400 boost::iostreams::stream_offset seek( boost::iostreams::stream_offset off, std::ios_base::seekdir way)
00401 {
00402 if( way == std::ios_base::beg ) {
00403 mStream->seekAbsolute( (off_t)off );
00404 }
00405 else if( way == std::ios_base::cur ) {
00406 mStream->seekRelative( (off_t)off );
00407 }
00408 else {
00409 mStream->seekAbsolute( -(off_t)off );
00410 }
00411 return mStream->tell();
00412 }
00413
00414 protected:
00415 IoStreamRef mStream;
00416 };
00417
00418 typedef boost::iostreams::stream<cinder_stream_bidirectional_device> cinder_iostream;
00419
00420 #endif // ! __OBJC__
00421
00422 }