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