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 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; // 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 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; // actual offset to do IO from; incremented by IO 00182 off_t mBufferFileOffset; // beginning of the buffer in the file 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; // actual offset to do IO from; incremented by IO 00244 off_t mBufferFileOffset; // beginning of the buffer in the file 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 // This class is a utility to save and restore a stream's state 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 // Stream exception 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; // a little kludgy but this is for convenience 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 { // way == std::ios_base::end 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 } // namespace cinder