00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "CeylanMemoryStream.h"
00028
00029 #include "CeylanLogPlug.h"
00030 #include "CeylanOperators.h"
00031 #include "CeylanStringUtils.h"
00032
00033
00034 #ifdef CEYLAN_USES_CONFIG_H
00035 #include "CeylanConfig.h"
00036 #endif // CEYLAN_USES_CONFIG_H
00037
00038
00039 extern "C"
00040 {
00041
00042 #ifdef CEYLAN_USES_STRING_H
00043 #include <string.h>
00044 #endif // CEYLAN_USES_STRING_H
00045
00046 }
00047
00048
00049 #include <climits>
00050
00051
00052
00053 #define CEYLAN_DEBUG_MEMORY_STREAM 0
00054
00055 #if CEYLAN_DEBUG_MEMORY_STREAM
00056
00057 #define DISPLAY_DEBUG_MEMORY_STREAM(message) LogPlug::debug(message)
00058
00059 #else // CEYLAN_DEBUG_MEMORY_STREAM
00060
00061 #define DISPLAY_DEBUG_MEMORY_STREAM(message)
00062
00063 #endif // CEYLAN_DEBUG_MEMORY_STREAM
00064
00065
00066 using std::string ;
00067
00068
00069 using namespace Ceylan::System ;
00070 using namespace Ceylan::Log ;
00071
00072
00073
00074
00075
00076 MemoryStream::MemoryStreamException::MemoryStreamException(
00077 const string & reason ) :
00078 SystemException( reason )
00079 {
00080
00081 }
00082
00083
00084
00085 MemoryStream::MemoryStreamException::~MemoryStreamException() throw()
00086 {
00087
00088 }
00089
00090
00091
00092 MemoryStream::MemoryStream( Size bufferSize ) :
00093 InputOutputStream(),
00094 _size( bufferSize ),
00095 _index( 0 ),
00096 _len( 0 ),
00097 _buffer()
00098 {
00099
00100 _buffer = new Ceylan::Byte[ bufferSize ] ;
00101
00102 }
00103
00104
00105
00106 MemoryStream::~MemoryStream() throw()
00107 {
00108
00109 delete [] _buffer ;
00110
00111 }
00112
00113
00114
00115 void MemoryStream::blank()
00116 {
00117
00118 _index = 0 ;
00119 _len = 0 ;
00120
00121 }
00122
00123
00124
00125 bool MemoryStream::close()
00126 {
00127
00128 return false ;
00129
00130 }
00131
00132
00133
00134 Size MemoryStream::getSize() const
00135 {
00136
00137 return _size ;
00138
00139 }
00140
00141
00142
00143 Size MemoryStream::read( Ceylan::Byte * buffer, Size maxLength )
00144 {
00145
00146 #ifdef CEYLAN_USES_MEMCPY
00147
00148 DISPLAY_DEBUG_MEMORY_STREAM( "MemoryStream::read of "
00149 + Ceylan::toString( maxLength ) + " byte(s), begin: " + toString() ) ;
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 if ( maxLength > _len )
00162 throw ReadFailedException( "MemoryStream::read: "
00163 "attempt to read more than available in the buffer: "
00164 + toString() ) ;
00165
00166
00167
00168
00169
00170
00171
00172
00173 if ( _index + maxLength > _size )
00174 {
00175
00176 DISPLAY_DEBUG_MEMORY_STREAM(
00177 "MemoryStream::read: two blocks needed" ) ;
00178
00179
00180
00181
00182
00183
00184
00185 Size firstBlockLen = _size - _index ;
00186 ::memcpy( buffer, _buffer + _index, firstBlockLen ) ;
00187 ::memcpy( buffer + firstBlockLen, _buffer, maxLength - firstBlockLen ) ;
00188
00189
00190 }
00191 else
00192 {
00193
00194 DISPLAY_DEBUG_MEMORY_STREAM(
00195 "MemoryStream::read: one block is enough" ) ;
00196
00197
00198 ::memcpy( buffer, _buffer + _index, maxLength ) ;
00199
00200 }
00201
00202 _index = ( _index + maxLength ) % _size ;
00203 _len -= maxLength ;
00204
00205
00206
00207
00208
00209
00210
00211 if ( _len == 0 )
00212 _index = 0 ;
00213
00214 DISPLAY_DEBUG_MEMORY_STREAM( "MemoryStream::read end: " + toString() ) ;
00215
00216 return maxLength ;
00217
00218 #else // CEYLAN_USES_MEMCPY
00219
00220 throw InputStream::ReadFailedException( "MemoryStream::read: "
00221 "not supported on this platform" ) ;
00222
00223 #endif // CEYLAN_USES_MEMCPY
00224
00225 }
00226
00227
00228
00229 bool MemoryStream::hasAvailableData() const
00230 {
00231
00232 return _len > 0 ;
00233
00234 }
00235
00236
00237
00238 Size MemoryStream::write( const string & message )
00239 {
00240
00241 return write( message.c_str(), message.size() ) ;
00242
00243 }
00244
00245
00246
00247 Size MemoryStream::write( const Ceylan::Byte * buffer, Size maxLength )
00248 {
00249
00250 DISPLAY_DEBUG_MEMORY_STREAM( "MemoryStream::write of "
00251 + Ceylan::toString( maxLength ) + " byte(s), begin: " + toString() ) ;
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 Size maxPossibleWriteSize = _size - _len ;
00263
00264 DISPLAY_DEBUG_MEMORY_STREAM( "Max size for writing: "
00265 + Ceylan::toString( maxPossibleWriteSize ) ) ;
00266
00267
00268 if ( maxLength > maxPossibleWriteSize )
00269 throw WriteFailedException( "MemoryStream::write: "
00270 "attempt to write more than free space in buffer (which is "
00271 + Ceylan::toString(
00272 static_cast<Ceylan::Uint32>( maxPossibleWriteSize ) )
00273 + " byte(s)): " + toString() ) ;
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 Size endOfBlock = ( _index + _len ) % _size ;
00284 if ( endOfBlock + maxLength > _size )
00285 {
00286
00287 DISPLAY_DEBUG_MEMORY_STREAM(
00288 "MemoryStream::write: two blocks needed" ) ;
00289
00290
00291
00292
00293
00294
00295 Size firstBlockLen = _size - endOfBlock ;
00296 ::memcpy( _buffer + endOfBlock, buffer, firstBlockLen ) ;
00297 ::memcpy( _buffer, buffer + firstBlockLen, maxLength - firstBlockLen ) ;
00298
00299 }
00300 else
00301 {
00302
00303 DISPLAY_DEBUG_MEMORY_STREAM(
00304 "MemoryStream::write: one block is enough" ) ;
00305
00306
00307 ::memcpy( _buffer + endOfBlock, buffer, maxLength ) ;
00308
00309
00310 }
00311
00312 _len += maxLength ;
00313
00314 DISPLAY_DEBUG_MEMORY_STREAM( "MemoryStream::write end: " + toString() ) ;
00315
00316 return maxLength ;
00317
00318 }
00319
00320
00321
00322
00323
00324
00325
00326 MemoryStream::Index MemoryStream::getIndexOfNextFreeChunk() const
00327 {
00328
00329 return ( _index + _len ) % _size ;
00330
00331 }
00332
00333
00334
00335 Ceylan::Byte * MemoryStream::getAddressOfNextFreeChunk() const
00336 {
00337
00338 return _buffer + getIndexOfNextFreeChunk() ;
00339
00340 }
00341
00342
00343
00344 Size MemoryStream::getSizeOfNextFreeChunk() const
00345 {
00346
00347 if ( ( _index + _len ) > _size )
00348 return _index - getIndexOfNextFreeChunk() ;
00349 else
00350 return _size - getIndexOfNextFreeChunk() ;
00351
00352 }
00353
00354
00355
00356 MemoryStream::Index MemoryStream::getBlockIndex() const
00357 {
00358
00359 return _index ;
00360
00361 }
00362
00363
00364
00365 Size MemoryStream::getBlockLength() const
00366 {
00367
00368 return _len ;
00369
00370 }
00371
00372
00373
00374 Ceylan::Byte MemoryStream::getElementAt( Index targetIndex ) const
00375 {
00376
00377 return _buffer[ targetIndex % _size ] ;
00378
00379 }
00380
00381
00382
00383 void MemoryStream::increaseFilledBlockOf( Size bytesAdded )
00384 {
00385
00386 if ( bytesAdded > getSizeOfNextFreeChunk() )
00387 throw MemoryStreamException( "MemoryStream::increaseFilledBlockOf: "
00388 " would not fit in buffer." ) ;
00389 _len += bytesAdded ;
00390
00391 }
00392
00393
00394
00395 void MemoryStream::moveFilledBlockToBufferStart()
00396 {
00397
00398 if ( _index == 0 )
00399 return ;
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 Ceylan::Byte * _permutedBuffer = new Ceylan::Byte[ _size ] ;
00412
00413
00414 if ( _index + _len > _size )
00415 {
00416
00417
00418 Size firstChunkSize = _size - _index ;
00419
00420 ::memcpy( _permutedBuffer, _buffer + _index, firstChunkSize ) ;
00421
00422
00423 ::memcpy( _permutedBuffer + firstChunkSize, _buffer,
00424 _len - firstChunkSize ) ;
00425
00426 }
00427 else
00428 {
00429
00430
00431 ::memcpy( _permutedBuffer, _buffer + _index, _len ) ;
00432
00433 }
00434
00435
00436 delete [] _buffer ;
00437
00438 _buffer = _permutedBuffer ;
00439
00440 _index = 0 ;
00441
00442
00443 }
00444
00445
00446
00447 StreamID MemoryStream::getStreamID() const
00448 {
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459 #if CEYLAN_ARCH_WINDOWS
00460
00461 return static_cast<StreamID>(
00462 reinterpret_cast<Ceylan::Uint64>( this ) ) ;
00463
00464 #else // CEYLAN_ARCH_WINDOWS
00465
00466
00467
00468
00469
00470
00471 return static_cast<StreamID>(
00472 reinterpret_cast<long>( this ) ) ;
00473
00474 #endif // CEYLAN_ARCH_WINDOWS
00475
00476 }
00477
00478
00479
00480 StreamID MemoryStream::getInputStreamID() const
00481 {
00482
00483 return getStreamID() ;
00484
00485 }
00486
00487
00488
00489 StreamID MemoryStream::getOutputStreamID() const
00490 {
00491
00492 return getStreamID() ;
00493
00494 }
00495
00496
00497
00498 const std::string MemoryStream::toString( Ceylan::VerbosityLevels level ) const
00499 {
00500
00501 string res = "MemoryStream object of size "
00502 + Ceylan::toString( static_cast<Ceylan::Uint32>( _size ) )
00503 + " bytes, whose fill index position is "
00504 + Ceylan::toString( static_cast<Ceylan::Uint32>( _index ) )
00505 + ", whose fill length is "
00506 + Ceylan::toString( static_cast<Ceylan::Uint32>( _len ) )
00507 + " byte(s), whose ID is "
00508 + Ceylan::toString( getStreamID() ) ;
00509
00510 if ( level != Ceylan::high )
00511 return res ;
00512
00513 res += ". Displaying buffer content: [ " ;
00514
00515 for ( Index i = 0 ; i < _size-1 ; i++ )
00516 {
00517 res += Ceylan::toNumericalString( getElementAt( i ) ) + "-" ;
00518 }
00519
00520 res += Ceylan::toNumericalString( getElementAt( _size ) ) ;
00521
00522 return res + " ]" ;
00523
00524 }
00525