# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

mem_stream.h

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #ifndef NL_MEM_STREAM_H
00027 #define NL_MEM_STREAM_H
00028 
00029 #include "nel/misc/types_nl.h"
00030 #include "nel/misc/stream.h"
00031 #include "nel/misc/object_vector.h"
00032 #include "nel/misc/fast_mem.h"
00033 
00034 namespace NLMISC
00035 {
00036 
00038 struct EMemStream : public NLMISC::EStream
00039 {
00040         EMemStream( const std::string& str ) : EStream( str ) {}
00041 };
00042 
00044 struct EStreamOverflow : public EMemStream
00045 {
00046         EStreamOverflow() : EMemStream( "Stream Overflow Error" ) {}
00047 };
00048 
00049 /*
00051 typedef std::vector<uint8> CVector8;
00052 
00054 typedef CVector8::iterator It8;
00055 */
00056 
00057 
00064 class CMemStream : public NLMISC::IStream
00065 {
00066 public:
00067 
00069         CMemStream( bool inputStream=false, bool stringmode=false, uint32 defaultcapacity=0 ) :
00070                 NLMISC::IStream( inputStream ), _StringMode( stringmode )
00071         {
00072                 _DefaultCapacity = std::max( defaultcapacity, (uint32)16 ); // prevent from no allocation
00073                 _Buffer.resize (_DefaultCapacity);
00074                 _BufPos = _Buffer.getPtr();
00075         }
00076 
00078         CMemStream( const CMemStream& other ) :
00079                 IStream (other)
00080         {
00081                 operator=( other );
00082         }
00083 
00085         CMemStream&             operator=( const CMemStream& other )
00086         {
00087                 IStream::operator= (other);
00088                 _Buffer = other._Buffer;
00089                 _BufPos = _Buffer.getPtr() + other.lengthS();
00090                 _StringMode = other._StringMode;
00091                 _DefaultCapacity = other._DefaultCapacity;
00092                 return *this;
00093         }
00094 
00096         void                    setStringMode( bool stringmode ) { _StringMode = stringmode; }
00097 
00099         bool                    stringMode() const { return _StringMode; }
00100 
00102         virtual void    serialBuffer(uint8 *buf, uint len);
00103 
00105         virtual void    serialBit(bool &bit);
00106 
00118         virtual bool    seek (sint32 offset, TSeekOrigin origin) throw(EStream);
00119 
00131         virtual sint32  getPos () throw(EStream)
00132         {
00133                 return _BufPos - _Buffer.getPtr();
00134         }
00135 
00137         virtual void    clear()
00138         {
00139                 resetPtrTable();
00140                 _Buffer.clear();
00141                 if (!isReading())
00142                 {
00143                         _Buffer.resize (_DefaultCapacity);
00144                 }
00145                 _BufPos = _Buffer.getPtr();
00146         }
00147 
00152         virtual uint32  length() const
00153         {
00154                 if ( isReading() )
00155                 {
00156                         return lengthR();
00157                 }
00158                 else
00159                 {
00160                         return lengthS();
00161                 }
00162         }
00163 
00167         const uint8             *buffer() const
00168         {
00169                 return _Buffer.getPtr();
00170 /*              if ( _Buffer.empty() )
00171                 {
00172                         return NULL;
00173                 }
00174                 else
00175                 {
00176                         return &(*_Buffer.begin());
00177                 }*/
00178         }
00179 
00180 /*      
00181         const CVector8& bufferAsVector() const
00182         {
00183                 return _Buffer;
00184         }
00185 
00187         CVector8&       bufferAsVector()
00188         {
00189                 return _Buffer;
00190         }
00191 */
00192         // When you fill the buffer externaly (using bufferAsVector) you have to reset the BufPos calling this method
00193         void resetBufPos() { _BufPos = _Buffer.getPtr(); }
00194 
00196         void                    fill( const uint8 *srcbuf, uint32 len )
00197         {
00198                 if (len == 0) return;
00199 
00200                 _Buffer.resize( len );
00201                 CFastMem::memcpy( _Buffer.getPtr(), srcbuf, len );
00202                 if (isReading())
00203                 {
00204                         _BufPos = _Buffer.getPtr();
00205                 }
00206                 else
00207                 {
00208                         _BufPos = _Buffer.getPtr() + _Buffer.size();
00209                 }
00210         }
00211 
00212         void resize (uint32 size);
00213 
00218         uint8                   *bufferToFill( uint32 msgsize )
00219         {
00220                 if (msgsize == 0) return NULL;
00221 
00222                 // Same as fill() but the memcpy is done by an external function
00223                 _Buffer.resize( msgsize );
00224                 _BufPos = _Buffer.getPtr() + msgsize;
00225                 return _Buffer.getPtr();
00226         }
00227 
00229         virtual void    invert()
00230         {
00231                 if ( isReading() )
00232                 {
00233                         // In->Out: We want to write (serialize out) what we have read (serialized in)
00234                         resetPtrTable();
00235                         setInOut( false );
00236                         _BufPos = _Buffer.getPtr()+_Buffer.size();
00237                 }
00238                 else
00239                 {
00240                         // Out->In: We want to read (serialize in) what we have written (serialized out)
00241                         resetPtrTable();
00242                         setInOut( true );
00243                         _Buffer.resize (_BufPos - _Buffer.getPtr());
00244                         _BufPos = _Buffer.getPtr();
00245                 }
00246         }
00247 
00249         void                    resetPtrTable() { IStream::resetPtrTable() ; }
00250 
00252 #ifdef NL_OS_WINDOWS
00253         __forceinline
00254 #endif
00255         void                    increaseBufferIfNecessary(uint32 len)
00256         {
00257                 uint32 oldBufferSize = _Buffer.size();
00258                 if (_BufPos - _Buffer.getPtr() + len > oldBufferSize)
00259                 {
00260                         // need to increase the buffer size
00261                         uint32 pos = _BufPos - _Buffer.getPtr();
00262                         _Buffer.resize(oldBufferSize*2 + len);
00263                         _BufPos = _Buffer.getPtr() + pos;
00264                 }
00265         }
00266 
00267 
00268         template <class T> void fastSerial (T &val)
00269         {
00270 #ifdef NL_LITTLE_ENDIAN
00271                 if(isReading())
00272                 {
00273                         // Check that we don't read more than there is to read
00274                         // TODO OPTIM we can remove the check if we want to be faster (50ms->43ms for 1 million serial)
00275                         if ( lengthS()+sizeof(T) > lengthR() )
00276                                 throw EStreamOverflow();
00277                         // Serialize in
00278                         val = *(T*)_BufPos;
00279                 }
00280                 else
00281                 {
00282                         increaseBufferIfNecessary (sizeof(T));
00283                         *(T*)_BufPos = val;
00284                 }
00285                 _BufPos += sizeof (T);
00286 #else // NL_LITTLE_ENDIAN
00287                 IStream::serial( val );
00288 #endif // NL_LITTLE_ENDIAN
00289         }
00290 
00291         template <class T>
00292         void                    fastWrite( T& value )
00293         {
00294                 //nldebug( "MEMSTREAM: Writing %u-byte value in %p at pos %u", sizeof(value), this, _BufPos - _Buffer.getPtr() );
00295                 increaseBufferIfNecessary (sizeof(T));
00296                 *(T*)_BufPos = value;
00297                 _BufPos += sizeof (T);
00298         }
00299 
00300         template <class T>
00301         void                    fastRead( T& value )
00302         {
00303                 //nldebug( "MEMSTREAM: Reading %u-byte value in %p at pos %u", sizeof(value), this, _BufPos - _Buffer.getPtr() );
00304                 // Check that we don't read more than there is to read
00305                 if ( lengthS()+sizeof(value) > lengthR() )
00306                 {
00307                         throw EStreamOverflow();
00308                 }
00309                 // Serialize in
00310                 value = *(T*)_BufPos;
00311                 _BufPos += sizeof(value);
00312         }
00313 
00314 
00316     template<class T>
00317         void                    serial(T &obj)                                                  { obj.serial(*this); }
00318 
00319         template<class T>
00320         void                    serialCont(std::vector<T> &cont)                {IStream::serialCont(cont);}
00321         template<class T>
00322         void                    serialCont(std::list<T> &cont)                  {IStream::serialCont(cont);}
00323         template<class T>
00324         void                    serialCont(std::deque<T> &cont)                 {IStream::serialCont(cont);}
00325         template<class T>
00326         void                    serialCont(std::set<T> &cont)                   {IStream::serialCont(cont);}
00327         template<class T>
00328         void                    serialCont(std::multiset<T> &cont)              {IStream::serialCont(cont);}
00329         template<class K, class T>
00330         void                    serialCont(std::map<K, T> &cont)                {IStream::serialCont(cont);}
00331         template<class K, class T>
00332         void                    serialCont(std::multimap<K, T> &cont)   {IStream::serialCont(cont);}
00333 
00335         virtual void                    serialCont(std::vector<uint8> &cont) {IStream::serialCont(cont);} 
00337         virtual void                    serialCont(std::vector<sint8> &cont) {IStream::serialCont(cont);} 
00339         virtual void                    serialCont(std::vector<bool> &cont) {IStream::serialCont(cont);} 
00340 
00341 
00342 
00343         template<class T0,class T1>
00344         void                    serial(T0 &a, T1 &b) 
00345         { serial(a); serial(b);}
00346         template<class T0,class T1,class T2>
00347         void                    serial(T0 &a, T1 &b, T2 &c) 
00348         { serial(a); serial(b); serial(c);}
00349         template<class T0,class T1,class T2,class T3>
00350         void                    serial(T0 &a, T1 &b, T2 &c, T3 &d) 
00351         { serial(a); serial(b); serial(c); serial(d);}
00352         template<class T0,class T1,class T2,class T3,class T4>
00353         void                    serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e) 
00354         { serial(a); serial(b); serial(c); serial(d); serial(e);}
00355         template<class T0,class T1,class T2,class T3,class T4,class T5>
00356         void                    serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e, T5 &f) 
00357         { serial(a); serial(b); serial(c); serial(d); serial(e); serial(f);}
00358 
00363         virtual void    serial(uint8 &b) ;
00364         virtual void    serial(sint8 &b) ;
00365         virtual void    serial(uint16 &b) ;
00366         virtual void    serial(sint16 &b) ;
00367         virtual void    serial(uint32 &b) ;
00368         virtual void    serial(sint32 &b) ;
00369         virtual void    serial(uint64 &b) ;
00370         virtual void    serial(sint64 &b) ;
00371         virtual void    serial(float &b) ;
00372         virtual void    serial(double &b) ;
00373         virtual void    serial(bool &b) ;
00374 #ifndef NL_OS_CYGWIN
00375         virtual void    serial(char &b) ;
00376 #endif
00377         virtual void    serial(std::string &b) ;
00378         virtual void    serial(ucstring &b) ;
00380 
00381 
00383 
00384 
00386         uint                    serialSeparatedBufferIn( uint8 *buf, uint len );
00387 
00389         void                    serialSeparatedBufferOut( uint8 *buf, uint len );
00390 
00392         virtual void    serialHex(uint32 &b);
00393 
00395 
00396 protected:
00397 
00399         uint32                  lengthS() const
00400         {
00401                 return _BufPos-_Buffer.getPtr();
00402         }
00403 
00405         uint32                  lengthR() const
00406         {
00407 //              return _BufPos-_Buffer.getPtr();
00408                 return _Buffer.size();
00409         }
00410 
00411         CObjectVector<uint8, false> _Buffer;
00412         uint8 *_BufPos;
00413         
00414         //CVector8              _Buffer;
00415         //It8                           _BufPos;
00416         bool                    _StringMode;
00417 
00418         uint32                  _DefaultCapacity;
00419 };
00420 
00421 // Input
00422 #define readnumber(dest,thetype,digits,convfunc) \
00423         char number_as_cstring [digits+1]; \
00424         uint realdigits = serialSeparatedBufferIn( (uint8*)&number_as_cstring, digits ); \
00425         number_as_cstring[realdigits] = '\0'; \
00426         dest = (thetype)convfunc( number_as_cstring );
00427 
00428 // Output
00429 #define writenumber(src,format,digits) \
00430         char number_as_cstring [digits+1]; \
00431         sprintf( number_as_cstring, format, src ); \
00432         serialSeparatedBufferOut( (uint8*)&number_as_cstring, strlen(number_as_cstring) );
00433 
00434 /*
00435  * atoihex
00436  */
00437 inline int atoihex( const char* ident )
00438 {
00439         int number;
00440         sscanf( ident, "%x", &number );
00441         return number;
00442 }
00443 
00444 inline uint32 atoui( const char *ident)
00445 {
00446         return (uint32) strtoul (ident, NULL, 10);
00447 }
00448 
00449 const char SEPARATOR = ' ';
00450 const int SEP_SIZE = 1; // the code is easier to read with that
00451 
00452 //
00453 // inline serial functions
00454 //
00455 
00456 
00457 // ======================================================================================================
00458 inline  void            CMemStream::serial(uint8 &b) 
00459 {
00460         if ( _StringMode )
00461         {
00462                 if ( isReading() )
00463                 {
00464                         readnumber( b, uint8, 3, atoi ); // 255
00465                 }
00466                 else
00467                 {
00468                         writenumber( (uint16)b,"%hu", 3 );
00469                 }
00470         }
00471         else
00472         {
00473                 fastSerial (b);
00474         }
00475 }
00476 
00477 // ======================================================================================================
00478 inline  void            CMemStream::serial(sint8 &b) 
00479 {
00480         if ( _StringMode )
00481         {
00482                 if ( isReading() )
00483                 {
00484                         readnumber( b, sint8, 4, atoi ); // -128
00485                 }
00486                 else
00487                 {
00488                         writenumber( (sint16)b, "%hd", 4 );
00489                 }
00490         }
00491         else
00492         {
00493                 fastSerial (b);
00494         }
00495 }
00496 
00497 // ======================================================================================================
00498 inline  void            CMemStream::serial(uint16 &b) 
00499 {
00500         if ( _StringMode )
00501         {
00502                 // No byte swapping in text mode
00503                 if ( isReading() )
00504                 {
00505                         readnumber( b, uint16, 5, atoi ); // 65535
00506                 }
00507                 else
00508                 {
00509                         writenumber( b, "%hu", 5 );
00510                 }
00511         }
00512         else
00513         {
00514                 fastSerial (b);
00515         }
00516 }
00517 
00518 // ======================================================================================================
00519 inline  void            CMemStream::serial(sint16 &b) 
00520 {
00521         if ( _StringMode )
00522         {
00523                 if ( isReading() )
00524                 {
00525                         readnumber( b, sint16, 6, atoi ); // -32768
00526                 }
00527                 else
00528                 {
00529                         writenumber( b, "%hd", 6 );
00530                 }
00531         }
00532         else
00533         {
00534                 fastSerial (b);
00535         }
00536 }
00537 
00538 // ======================================================================================================
00539 inline  void            CMemStream::serial(uint32 &b) 
00540 {
00541         if ( _StringMode )
00542         {
00543                 if ( isReading() )
00544                 {
00545                         readnumber( b, uint32, 10, atoui ); // 4294967295
00546                 }
00547                 else
00548                 {
00549                         writenumber( b, "%u", 10 );
00550                 }
00551         }
00552         else
00553         {
00554                 fastSerial (b);
00555         }
00556 }
00557 
00558 
00559 // ======================================================================================================
00560 inline  void            CMemStream::serial(sint32 &b) 
00561 {
00562         if ( _StringMode )
00563         {
00564                 if ( isReading() )
00565                 {
00566                         readnumber( b, sint32, 11, atoi ); // -2147483648
00567                 }
00568                 else
00569                 {
00570                         writenumber( b, "%d", 11 );
00571                 }
00572         }
00573         else
00574         {
00575                 fastSerial (b);
00576         }
00577 }
00578 
00579 // ======================================================================================================
00580 inline  void            CMemStream::serial(uint64 &b) 
00581 {
00582         if ( _StringMode )
00583         {
00584                 if ( isReading() )
00585                 {
00586                         readnumber( b, uint64, 20, atoiInt64 ); // 18446744073709551615
00587                 }
00588                 else
00589                 {
00590                         writenumber( b, "%"NL_I64"u", 20 );
00591                 }
00592         }
00593         else
00594         {
00595                 fastSerial (b);
00596         }
00597 }
00598 
00599 // ======================================================================================================
00600 inline  void            CMemStream::serial(sint64 &b) 
00601 {
00602         if ( _StringMode )
00603         {
00604                 if ( isReading() )
00605                 {
00606                         readnumber( b, sint64, 20, atoiInt64 ); // -9223372036854775808
00607                 }
00608                 else
00609                 {
00610                         writenumber( b, "%"NL_I64"d", 20 );
00611                 }
00612         }
00613         else
00614         {
00615                 fastSerial (b);
00616         }
00617 }
00618 
00619 // ======================================================================================================
00620 inline  void            CMemStream::serial(float &b) 
00621 {
00622         if ( _StringMode )
00623         {
00624                 if ( isReading() )
00625                 {
00626                         readnumber( b, float, 128, atof ); // ?
00627                 }
00628                 else
00629                 {
00630                         writenumber( (double)b, "%f", 128 );
00631                 }
00632         }
00633         else
00634         {
00635                 fastSerial (b);
00636         }
00637 }
00638 
00639 // ======================================================================================================
00640 inline  void            CMemStream::serial(double &b) 
00641 {
00642         if ( _StringMode )
00643         {
00644                 if ( isReading() )
00645                 {
00646                         readnumber( b, double, 128, atof ); //
00647                 }
00648                 else
00649                 {
00650                         writenumber( b, "%f", 128 );
00651                 }
00652         }
00653         else
00654         {
00655                 fastSerial (b);
00656         }
00657 }
00658 
00659 // ======================================================================================================
00660 inline  void            CMemStream::serial(bool &b) 
00661 {
00662         if ( _StringMode )
00663         {
00664                 serialBit(b);
00665         }
00666         else
00667         {
00668                 fastSerial (b);
00669         }
00670 }
00671 
00672 
00673 #ifndef NL_OS_CYGWIN
00674 // ======================================================================================================
00675 inline  void            CMemStream::serial(char &b) 
00676 {
00677         if ( _StringMode )
00678         {
00679                 char buff [2];
00680                 if ( isReading() )
00681                 {
00682                         serialBuffer( (uint8*)buff, 2 );
00683                         b = buff[0];
00684                 }
00685                 else
00686                 {
00687                         buff[0] = b;
00688                         buff[1] = SEPARATOR;
00689                         serialBuffer( (uint8*)buff, 2 );
00690                 }
00691         }
00692         else
00693         {
00694                 fastSerial (b);
00695         }
00696 }
00697 #endif
00698 
00699 // ======================================================================================================
00700 inline  void            CMemStream::serial(std::string &b) 
00701 {
00702         if ( _StringMode )
00703         {
00704                 sint32  len=0;
00705                 // Read/Write the length.
00706                 if(isReading())
00707                 {
00708                         serial(len);
00709                         nlassert( len<1000000 ); // limiting string size
00710                         b.resize(len);
00711                 }
00712                 else
00713                 {
00714                         len= b.size();
00715                         serial(len);
00716                 }
00717                 
00718                 // Read/Write the string.
00719                 for(sint i=0;i<len;i++)
00720                         serialBuffer( (uint8*)&(b[i]), sizeof(b[i]) );
00721 
00722                 char sep = SEPARATOR;
00723                 serialBuffer( (uint8*)&sep, 1 );
00724         }
00725         else
00726         {
00727                 IStream::serial( b );
00728         }
00729 }
00730 
00731 
00732 // ======================================================================================================
00733 inline  void            CMemStream::serial(ucstring &b) 
00734 {
00735         if ( _StringMode )
00736         {
00737                 sint32  len=0;
00738                 // Read/Write the length.
00739                 if(isReading())
00740                 {
00741                         serial(len);
00742                         b.resize(len);
00743                 }
00744                 else
00745                 {
00746                         len= b.size();
00747                         serial(len);
00748                 }
00749                 // Read/Write the string.
00750                 for(sint i=0;i<len;i++)
00751                         serialBuffer( (uint8*)&b[i], sizeof( sizeof(b[i]) ) );
00752 
00753                 char sep = SEPARATOR;
00754                 serialBuffer( (uint8*)&sep, 1 );
00755         }
00756         else
00757         {
00758                 IStream::serial( b );
00759         }
00760 }
00761 
00762 
00763 // Specialisation of serialCont() for vector<bool>
00764 /*inline        void    CMemStream::serialCont(std::vector<bool> &cont)
00765 {
00766         sint32  len=0;
00767         if(isReading())
00768         {
00769                 serial(len);
00770                 // special version for vector: adjut good size.
00771                 contReset(cont);
00772                 cont.reserve(len);
00773 
00774                 for(sint i=0;i<len;i++)
00775                 {
00776                         bool    v;
00777                         serial(v);
00778                         cont.insert(cont.end(), v);
00779                 }
00780         }
00781         else
00782         {
00783                 len= cont.size();
00784                 serial(len);
00785 
00786                 std::vector<bool>::iterator it= cont.begin();
00787                 for(sint i=0;i<len;i++, it++)
00788                 {
00789                         bool b = *it;
00790                         serial( b );
00791                 }
00792         }
00793 }*/
00794 
00795 
00796 /*
00797  * Serialisation in hexadecimal
00798  */
00799 inline  void    CMemStream::serialHex(uint32 &b)
00800 {
00801         if ( _StringMode )
00802         {
00803                 if ( isReading() )
00804                 {
00805                         readnumber( b, uint32, 10, atoihex ); // 4294967295
00806                 }
00807                 else
00808                 {
00809                         writenumber( b, "%x", 10 );
00810                 }
00811                 }
00812         else
00813         {
00814                 IStream::serial( b );
00815         }
00816 }
00817 
00818 
00819 
00820 
00821 
00822 
00823 
00824 
00825 }
00826 
00827 #endif // NL_MEM_STREAM_H
00828 
00829 /* End of mem_stream.h */