mem_stream.h

Go to the documentation of this file.
00001 
00005 /* Copyright, 2000 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #ifndef NL_MEM_STREAM_H
00025 #define NL_MEM_STREAM_H
00026 
00027 #include "types_nl.h"
00028 #include "stream.h"
00029 #include "object_vector.h"
00030 #include "fast_mem.h"
00031 #include "smart_ptr.h"
00032 
00033 #include <algorithm>
00034 
00035 namespace NLMISC
00036 {
00037 
00039 struct EMemStream : public NLMISC::EStream
00040 {
00041     EMemStream( const std::string& str ) : EStream( str ) {}
00042 };
00043 
00044 
00056 class CMemStreamBuffer
00057 {
00058 public:
00059     typedef CObjectVector<uint8, false> TBuffer;
00060 private:
00061     struct TMemStreamBuffer : public CRefCount
00062     {
00063         // the buffer himself
00064         TBuffer _Buffer;
00065     };
00066 
00067     typedef CSmartPtr<TMemStreamBuffer> TMemStreamBufferPtr;
00068 
00069     TMemStreamBufferPtr     _SharedBuffer;
00070 
00071 public:
00072 
00073     mutable uint32  Pos;
00074 
00076     CMemStreamBuffer()
00077     {
00078         _SharedBuffer = new TMemStreamBuffer;
00079         Pos = 0;
00080     }
00081 
00082 
00084     const TBuffer &getBuffer() const
00085     {
00086         return _SharedBuffer->_Buffer;
00087     }
00088 
00092     TBuffer &getBufferWrite()
00093     {
00094         if (_SharedBuffer->getRefCount() > 1)
00095         {
00096             // we need to duplicate the buffer
00097             _SharedBuffer = new TMemStreamBuffer(*_SharedBuffer);
00098         }
00099         return _SharedBuffer->_Buffer;
00100     }
00101 
00103     void swap(CMemStreamBuffer &other)
00104     {
00105         std::swap(_SharedBuffer, other._SharedBuffer);
00106         std::swap(Pos, other.Pos);
00107     }
00108 
00109 };
00110 
00111 
00140 class CMemStream : public NLMISC::IStream
00141 {
00142 public:
00143 
00145     CMemStream( bool inputStream=false, bool stringmode=false, uint32 defaultcapacity=0 ) :
00146         NLMISC::IStream( inputStream ), _StringMode( stringmode )
00147     {
00148         _DefaultCapacity = std::max( (uint32)defaultcapacity, (uint32)16 ); // prevent from no allocation
00149         _Buffer.getBufferWrite().resize (_DefaultCapacity);
00150         _Buffer.Pos = 0;
00151     }
00152 
00154     CMemStream( const CMemStream& other ) :
00155         IStream (other)
00156     {
00157         operator=( other );
00158     }
00159 
00161     CMemStream&     operator=( const CMemStream& other )
00162     {
00163         IStream::operator= (other);
00164         _Buffer = other._Buffer;
00165         _StringMode = other._StringMode;
00166         _DefaultCapacity = other._DefaultCapacity;
00167         return *this;
00168     }
00169 
00171     void swap(CMemStream &other);
00172 
00174     void            setStringMode( bool stringmode ) { _StringMode = stringmode; }
00175 
00177     bool            stringMode() const { return _StringMode; }
00178 
00183     std::string     toString( bool hexFormat=false ) const;
00184 
00186     virtual void    serialBuffer(uint8 *buf, uint len);
00187 
00189     virtual void    serialBit(bool &bit);
00190 
00207     virtual bool    seek (sint32 offset, TSeekOrigin origin) const throw(EStream);
00208 
00220     virtual sint32  getPos () const throw(EStream)
00221     {
00222         return sint32(_Buffer.Pos);
00223     }
00224 
00229     sint32          reserve( uint len )
00230     {
00231         sint32 pos = sint32(_Buffer.Pos);
00232         if ( ! isReading() )
00233         {
00234             increaseBufferIfNecessary( len );
00235             _Buffer.Pos += len;
00236         }
00237         return pos;
00238     }
00239 
00250     template <class T>
00251     void            poke( T value, sint32 pos )
00252     {
00253         if ( ! isReading() )
00254         {
00255             uint8 *pokeBufPos = _Buffer.getBufferWrite().getPtr() + pos;
00256             nlassert( pokeBufPos + sizeof(T) <= pokeBufPos+_Buffer.Pos );
00257             *(T*)pokeBufPos = value;
00258         }
00259     }
00260 
00262     virtual void    clear()
00263     {
00264         resetPtrTable();
00265         _Buffer.getBufferWrite().clear();
00266         if (!isReading())
00267         {
00268             _Buffer.getBufferWrite().resize (_DefaultCapacity);
00269         }
00270         _Buffer.Pos = 0;
00271     }
00272 
00278     virtual uint32  length() const
00279     {
00280         if ( isReading() )
00281         {
00282             return lengthR();
00283         }
00284         else
00285         {
00286             return lengthS();
00287         }
00288     }
00289 
00291     uint32          size() const
00292     {
00293         return _Buffer.getBuffer().size();
00294     }
00295 
00299     virtual const uint8     *buffer() const
00300     {
00301         return _Buffer.getBuffer().getPtr();
00302     }
00303 
00304 
00311     void            resetBufPos() { _Buffer.Pos = 0; }
00312 
00318     void            fill( const uint8 *srcbuf, uint32 len )
00319     {
00320         if (len == 0) return;
00321 
00322         _Buffer.getBufferWrite().resize( len );
00323         CFastMem::memcpy( _Buffer.getBufferWrite().getPtr(), srcbuf, len );
00324         if (isReading())
00325         {
00326             _Buffer.Pos = 0;
00327         }
00328         else
00329         {
00330             _Buffer.Pos = _Buffer.getBuffer().size();
00331         }
00332     }
00333 
00338     void            resize (uint32 size);
00339 
00350     uint8           *bufferToFill( uint32 msgsize )
00351     {
00352 #ifdef NL_DEBUG
00353         nlassert( isReading() );
00354 #endif
00355         if ( msgsize == 0 )
00356             return NULL;
00357 
00358         _Buffer.getBufferWrite().resize( msgsize );
00359         _Buffer.Pos = 0;
00360         return _Buffer.getBufferWrite().getPtr();
00361     }
00362 
00373     virtual void    invert()
00374     {
00375         if ( isReading() )
00376         {
00377             // In->Out: We want to write (serialize out) what we have read (serialized in)
00378             uint32 sizeOfReadStream = lengthR();
00379             resetPtrTable();
00380             setInOut( false );
00381             _Buffer.Pos = sizeOfReadStream;
00382         }
00383         else
00384         {
00385             // Out->In: We want to read (serialize in) what we have written (serialized out)
00386             resetPtrTable();
00387             setInOut( true );
00388             // TODO : is it necessary ?
00389             _Buffer.getBufferWrite().resize (_Buffer.Pos);
00390             _Buffer.Pos = 0;
00391         }
00392     }
00393 
00395     void            resetPtrTable() { IStream::resetPtrTable() ; }
00396 
00398 #ifdef NL_OS_WINDOWS
00399     __forceinline
00400 #endif
00401     void            increaseBufferIfNecessary(uint32 len)
00402     {
00403         uint32 oldBufferSize = _Buffer.getBuffer().size();
00404         if (_Buffer.Pos + len > oldBufferSize)
00405         {
00406             // need to increase the buffer size
00407             _Buffer.getBufferWrite().resize(oldBufferSize*2 + len);
00408         }
00409     }
00410 
00411 
00412     template <class T> void fastSerial (T &val)
00413     {
00414 #ifdef NL_LITTLE_ENDIAN
00415         if(isReading())
00416         {
00417             // Check that we don't read more than there is to read
00418             if ( lengthS()+sizeof(T) > length() ) // calls virtual length (cf. sub messages)
00419                 throw EStreamOverflow();
00420             // Serialize in
00421             val = *(T*)(_Buffer.getBuffer().getPtr() + _Buffer.Pos);
00422         }
00423         else
00424         {
00425             increaseBufferIfNecessary (sizeof(T));
00426             *(T*)(_Buffer.getBufferWrite().getPtr() + _Buffer.Pos) = val;
00427         }
00428         _Buffer.Pos += sizeof (T);
00429 #else // NL_LITTLE_ENDIAN
00430         IStream::serial( val );
00431 #endif // NL_LITTLE_ENDIAN
00432     }
00433 
00434     template <class T>
00435     void            fastWrite( const T& value )
00436     {
00437         //nldebug( "MEMSTREAM: Writing %u-byte value in %p at pos %u", sizeof(value), this, _BufPos - _Buffer.getPtr() );
00438         increaseBufferIfNecessary (sizeof(T));
00439         *(T*)(_Buffer.getBufferWrite().getPtr() + _Buffer.Pos) = value;
00440 
00441         _Buffer.Pos += sizeof (T);
00442     }
00443 
00444     template <class T>
00445     void            fastRead( T& value )
00446     {
00447         //nldebug( "MEMSTREAM: Reading %u-byte value in %p at pos %u", sizeof(value), this, _BufPos - _Buffer.getPtr() );
00448         // Check that we don't read more than there is to read
00449         if ( lengthS()+sizeof(value) > length() ) // calls virtual length (cf. sub messages)
00450         {
00451             throw EStreamOverflow();
00452         }
00453         // Serialize in
00454         value = *(T*)(_Buffer.getBuffer().getPtr() + _Buffer.Pos);
00455         _Buffer.Pos += sizeof(value);
00456     }
00457 
00458 
00460     template<class T>
00461     void            serial(T &obj)              { obj.serial(*this); }
00462 
00463 
00464     template<class T>
00465     void            serialCont(std::vector<T> &cont)        {IStream::serialCont(cont);}
00466     template<class T>
00467     void            serialCont(std::list<T> &cont)          {IStream::serialCont(cont);}
00468     template<class T>
00469     void            serialCont(std::deque<T> &cont)         {IStream::serialCont(cont);}
00470     template<class T>
00471     void            serialCont(std::set<T> &cont)           {IStream::serialCont(cont);}
00472     template<class T>
00473     void            serialCont(std::multiset<T> &cont)      {IStream::serialCont(cont);}
00474     template<class K, class T>
00475     void            serialCont(std::map<K, T> &cont)        {IStream::serialCont(cont);}
00476     template<class K, class T>
00477     void            serialCont(std::multimap<K, T> &cont)   {IStream::serialCont(cont);}
00479     virtual void            serialCont(std::vector<uint8> &cont) {IStream::serialCont(cont);}
00481     virtual void            serialCont(std::vector<sint8> &cont) {IStream::serialCont(cont);}
00483     virtual void            serialCont(std::vector<bool> &cont) {IStream::serialCont(cont);}
00484 
00485 
00486 
00487     template<class T0,class T1>
00488     void            serial(T0 &a, T1 &b)
00489     { serial(a); serial(b);}
00490     template<class T0,class T1,class T2>
00491     void            serial(T0 &a, T1 &b, T2 &c)
00492     { serial(a); serial(b); serial(c);}
00493     template<class T0,class T1,class T2,class T3>
00494     void            serial(T0 &a, T1 &b, T2 &c, T3 &d)
00495     { serial(a); serial(b); serial(c); serial(d);}
00496     template<class T0,class T1,class T2,class T3,class T4>
00497     void            serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e)
00498     { serial(a); serial(b); serial(c); serial(d); serial(e);}
00499     template<class T0,class T1,class T2,class T3,class T4,class T5>
00500     void            serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e, T5 &f)
00501     { serial(a); serial(b); serial(c); serial(d); serial(e); serial(f);}
00502 
00507     virtual void    serial(uint8 &b) ;
00508     virtual void    serial(sint8 &b) ;
00509     virtual void    serial(uint16 &b) ;
00510     virtual void    serial(sint16 &b) ;
00511     virtual void    serial(uint32 &b) ;
00512     virtual void    serial(sint32 &b) ;
00513     virtual void    serial(uint64 &b) ;
00514     virtual void    serial(sint64 &b) ;
00515     virtual void    serial(float &b) ;
00516     virtual void    serial(double &b) ;
00517     virtual void    serial(bool &b) ;
00518 #ifndef NL_OS_CYGWIN
00519     virtual void    serial(char &b) ;
00520 #endif
00521     virtual void    serial(std::string &b) ;
00522     virtual void    serial(ucstring &b) ;
00524 
00525 
00527 
00528 
00530     uint            serialSeparatedBufferIn( uint8 *buf, uint len );
00531 
00533     void            serialSeparatedBufferOut( uint8 *buf, uint len );
00534 
00536     virtual void    serialHex(uint32 &b);
00537 
00539 
00540 protected:
00541 
00543     virtual uint32          lengthS() const
00544     {
00545         return _Buffer.Pos; // not calling getPos() because virtual and not const!
00546     }
00547 
00552     uint32          lengthR() const
00553     {
00554         return size();
00555     }
00556 
00560     virtual uint            getDbgStreamSize() const;
00561 
00562     CMemStreamBuffer            _Buffer;
00563 
00564     mutable bool                _StringMode;
00565 
00566     uint32                      _DefaultCapacity;
00567 };
00568 
00569 // Input
00570 #define readnumber(dest,thetype,digits,convfunc) \
00571     char number_as_cstring [digits+1]; \
00572     uint realdigits = serialSeparatedBufferIn( (uint8*)number_as_cstring, digits ); \
00573     number_as_cstring[realdigits] = '\0'; \
00574     dest = (thetype)convfunc( number_as_cstring );
00575 
00576 // Output
00577 #define writenumber(src,format,digits) \
00578     char number_as_cstring [digits+1]; \
00579     sprintf( number_as_cstring, format, src ); \
00580     serialSeparatedBufferOut( (uint8*)number_as_cstring, strlen(number_as_cstring) );
00581 
00582 /*
00583  * atoihex
00584  */
00585 inline uint32 atoihex( const char* ident )
00586 {
00587     uint32 number;
00588     sscanf( ident, "%x", &number );
00589     return number;
00590 }
00591 
00592 inline uint32 atoui( const char *ident)
00593 {
00594     return (uint32) strtoul (ident, NULL, 10);
00595 }
00596 
00597 static const char SEPARATOR = ' ';
00598 static const int SEP_SIZE = 1; // the code is easier to read with that
00599 
00600 //
00601 // inline serial functions
00602 //
00603 
00604 
00605 // ======================================================================================================
00606 inline  void        CMemStream::serial(uint8 &b)
00607 {
00608     if ( _StringMode )
00609     {
00610         if ( isReading() )
00611         {
00612             readnumber( b, uint8, 3, atoi ); // 255
00613         }
00614         else
00615         {
00616             writenumber( (uint16)b,"%hu", 3 );
00617         }
00618     }
00619     else
00620     {
00621         fastSerial (b);
00622     }
00623 }
00624 
00625 // ======================================================================================================
00626 inline  void        CMemStream::serial(sint8 &b)
00627 {
00628     if ( _StringMode )
00629     {
00630         if ( isReading() )
00631         {
00632             readnumber( b, sint8, 4, atoi ); // -128
00633         }
00634         else
00635         {
00636             writenumber( (sint16)b, "%hd", 4 );
00637         }
00638     }
00639     else
00640     {
00641         fastSerial (b);
00642     }
00643 }
00644 
00645 // ======================================================================================================
00646 inline  void        CMemStream::serial(uint16 &b)
00647 {
00648     if ( _StringMode )
00649     {
00650         // No byte swapping in text mode
00651         if ( isReading() )
00652         {
00653             readnumber( b, uint16, 5, atoi ); // 65535
00654         }
00655         else
00656         {
00657             writenumber( b, "%hu", 5 );
00658         }
00659     }
00660     else
00661     {
00662         fastSerial (b);
00663     }
00664 }
00665 
00666 // ======================================================================================================
00667 inline  void        CMemStream::serial(sint16 &b)
00668 {
00669     if ( _StringMode )
00670     {
00671         if ( isReading() )
00672         {
00673             readnumber( b, sint16, 6, atoi ); // -32768
00674         }
00675         else
00676         {
00677             writenumber( b, "%hd", 6 );
00678         }
00679     }
00680     else
00681     {
00682         fastSerial (b);
00683     }
00684 }
00685 
00686 // ======================================================================================================
00687 inline  void        CMemStream::serial(uint32 &b)
00688 {
00689     if ( _StringMode )
00690     {
00691         if ( isReading() )
00692         {
00693             readnumber( b, uint32, 10, atoui ); // 4294967295
00694         }
00695         else
00696         {
00697             writenumber( b, "%u", 10 );
00698         }
00699     }
00700     else
00701     {
00702         fastSerial (b);
00703     }
00704 }
00705 
00706 
00707 // ======================================================================================================
00708 inline  void        CMemStream::serial(sint32 &b)
00709 {
00710     if ( _StringMode )
00711     {
00712         if ( isReading() )
00713         {
00714             readnumber( b, sint32, 11, atoi ); // -2147483648
00715         }
00716         else
00717         {
00718             writenumber( b, "%d", 11 );
00719         }
00720     }
00721     else
00722     {
00723         fastSerial (b);
00724     }
00725 }
00726 
00727 // ======================================================================================================
00728 inline  void        CMemStream::serial(uint64 &b)
00729 {
00730     if ( _StringMode )
00731     {
00732         if ( isReading() )
00733         {
00734             readnumber( b, uint64, 20, atoiInt64 ); // 18446744073709551615
00735         }
00736         else
00737         {
00738             writenumber( b, "%"NL_I64"u", 20 );
00739         }
00740     }
00741     else
00742     {
00743         fastSerial (b);
00744     }
00745 }
00746 
00747 // ======================================================================================================
00748 inline  void        CMemStream::serial(sint64 &b)
00749 {
00750     if ( _StringMode )
00751     {
00752         if ( isReading() )
00753         {
00754             readnumber( b, sint64, 20, atoiInt64 ); // -9223372036854775808
00755         }
00756         else
00757         {
00758             writenumber( b, "%"NL_I64"d", 20 );
00759         }
00760     }
00761     else
00762     {
00763         fastSerial (b);
00764     }
00765 }
00766 
00767 // ======================================================================================================
00768 inline  void        CMemStream::serial(float &b)
00769 {
00770     if ( _StringMode )
00771     {
00772         if ( isReading() )
00773         {
00774             readnumber( b, float, 128, atof ); // ?
00775         }
00776         else
00777         {
00778             writenumber( (double)b, "%f", 128 );
00779         }
00780     }
00781     else
00782     {
00783         fastSerial (b);
00784     }
00785 }
00786 
00787 // ======================================================================================================
00788 inline  void        CMemStream::serial(double &b)
00789 {
00790     if ( _StringMode )
00791     {
00792         if ( isReading() )
00793         {
00794             readnumber( b, double, 128, atof ); //
00795         }
00796         else
00797         {
00798             writenumber( b, "%f", 128 );
00799         }
00800     }
00801     else
00802     {
00803         fastSerial (b);
00804     }
00805 }
00806 
00807 // ======================================================================================================
00808 inline  void        CMemStream::serial(bool &b)
00809 {
00810     if ( _StringMode )
00811     {
00812         serialBit(b);
00813     }
00814     else
00815     {
00816         fastSerial (b);
00817     }
00818 }
00819 
00820 
00821 #ifndef NL_OS_CYGWIN
00822 // ======================================================================================================
00823 inline  void        CMemStream::serial(char &b)
00824 {
00825     if ( _StringMode )
00826     {
00827         char buff [2];
00828         if ( isReading() )
00829         {
00830             serialBuffer( (uint8*)buff, 2 );
00831             b = buff[0];
00832         }
00833         else
00834         {
00835             buff[0] = b;
00836             buff[1] = SEPARATOR;
00837             serialBuffer( (uint8*)buff, 2 );
00838         }
00839     }
00840     else
00841     {
00842         fastSerial (b);
00843     }
00844 }
00845 #endif
00846 
00847 // ======================================================================================================
00848 inline  void        CMemStream::serial(std::string &b)
00849 {
00850     if ( _StringMode )
00851     {
00852         uint32  len=0;
00853         // Read/Write the length.
00854         if(isReading())
00855         {
00856             serial(len);
00857             checkStreamSize((uint)len);
00858             /*if (len>1000000)
00859                 throw NLMISC::EInvalidDataStream( "CMemStream/str: Trying to read a string of %u bytes", len );
00860             */
00861             b.resize(len);
00862         }
00863         else
00864         {
00865             len= (uint32)b.size();
00866             if (len>1000000)
00867                 throw NLMISC::EInvalidDataStream( "CMemStream/str: Trying to write a string of %u bytes", len );
00868             serial(len);
00869         }
00870 
00871         // Read/Write the string.
00872         for(uint i=0;i!=len;++i)
00873             serialBuffer( (uint8*)&(b[i]), sizeof(b[i]) );
00874 
00875         char sep = SEPARATOR;
00876         serialBuffer( (uint8*)&sep, 1 );
00877     }
00878     else
00879     {
00880         if (isReading())
00881         {
00882             if (!isXML())
00883             {
00884                 uint32  len=0;
00885                 fastSerial(len);
00886                 checkStreamSize((uint)len);
00887                 /*
00888                 if (len>1000000)
00889                     throw NLMISC::EInvalidDataStream( "CMemStream: Trying to read a string of %u bytes", len );
00890                 */
00891                 b.resize(len);
00892                 if (len > 0)
00893                 {
00894                     // can serial all in a single call to serialBuffer, since sizeof(char) == 1
00895                     serialBuffer((uint8 *) &b[0], len);
00896                 }
00897             }
00898             else
00899             {
00900                 IStream::serial( b );
00901             }
00902         }
00903         else
00904         {
00905             IStream::serial( b );
00906         }
00907     }
00908 }
00909 
00910 
00911 // ======================================================================================================
00912 inline  void        CMemStream::serial(ucstring &b)
00913 {
00914     if ( _StringMode )
00915     {
00916         uint32  len=0;
00917         // Read/Write the length.
00918         if(isReading())
00919         {
00920             serial(len);
00921             checkStreamSize((uint)len);
00922             /*
00923             if (len>1000000)
00924                 throw NLMISC::EInvalidDataStream( "CMemStream/str: Trying to read an ucstring of %u bytes", len );
00925             */
00926             b.resize(len);
00927         }
00928         else
00929         {
00930             len= (uint32)b.size();
00931             if (len>1000000)
00932                 throw NLMISC::EInvalidDataStream( "CMemStream/str: Trying to write an ucstring of %u bytes", len );
00933             serial(len);
00934         }
00935         // Read/Write the string.
00936         for(uint i=0;i!=len;++i)
00937             serialBuffer( (uint8*)&b[i], sizeof(b[i]) );
00938 
00939         char sep = SEPARATOR;
00940         serialBuffer( (uint8*)&sep, 1 );
00941     }
00942     else
00943     {
00944         IStream::serial( b );
00945     }
00946 }
00947 
00948 
00949 
00950 /*
00951  * Serialisation in hexadecimal
00952  */
00953 inline  void    CMemStream::serialHex(uint32 &b)
00954 {
00955     if ( _StringMode )
00956     {
00957         if ( isReading() )
00958         {
00959             readnumber( b, uint32, 10, atoihex ); // 4294967295
00960         }
00961         else
00962         {
00963             writenumber( b, "%x", 10 );
00964         }
00965     }
00966     else
00967     {
00968         IStream::serial( b );
00969     }
00970 }
00971 
00972 }
00973 
00974 #endif // NL_MEM_STREAM_H
00975 
00976 /* End of mem_stream.h */

Generated on Thu Jan 7 08:26:22 2010 for NeL by  doxygen 1.6.1