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