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