1 /* 2 * Copyright 2002-2006, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Scott T. Mansfield, thephantom@mac.com 7 */ 8 9 /*! 10 Remarks: 11 * This is basically a fancy-schmancy FIFO stack manager. Thusly, it is 12 considered an error if data is not popped off a particular instance's 13 stack in the order it was pushed on. 14 * We could possibly implement this class as a thin wrapper around the 15 BMessage class, but I'm not sure what kind of payload the latter class 16 brings to the party, so we'll do our own stack management. We also 17 cannot be sure that BMessage behaves as described above down the road. 18 * Never use hot wax to soothe enraged lobsters. 19 */ 20 21 #include <ByteOrder.h> 22 #include <Message.h> 23 #include <NetBuffer.h> 24 25 #include <string.h> 26 27 28 /* 29 * Parametric ctor initialization list defaults. 30 */ 31 #define CTOR_INIT_LIST \ 32 BArchivable( ), \ 33 fInit( B_NO_INIT ), \ 34 fData( NULL ), \ 35 fDataSize( 0 ), \ 36 fStackSize( 0 ), \ 37 fCapacity( 0 ) 38 39 40 /* 41 * Markers that surround a record in an instance's stack. 42 */ 43 #define DATA_START_MARKER 0x01c0ffee 44 #define DATA_END_MARKER 0xbeefeeee 45 46 47 /* BNetBuffer 48 *=--------------------------------------------------------------------------=* 49 * Purpose: 50 * Class ctor. 51 * 52 * Input parameter: 53 * size : Initial size of buffer (default is zero). 54 * 55 * Remarks: 56 * This bad boy doubles up as the default ctor. 57 */ 58 BNetBuffer::BNetBuffer( size_t size ) 59 : CTOR_INIT_LIST 60 { 61 fInit = ( resize( size ) == B_OK ) ? B_OK : B_NO_INIT; 62 } 63 64 65 /* BNetBuffer 66 *=--------------------------------------------------------------------------=* 67 * Purpose: 68 * Class copy ctor. 69 * 70 * Input parameter: 71 * refparam : Instance to copy. 72 */ 73 BNetBuffer::BNetBuffer( const BNetBuffer& refparam ) 74 : CTOR_INIT_LIST 75 { 76 fInit = ( clone( refparam ) == B_OK ) ? B_OK : B_NO_INIT; 77 } 78 79 80 /* BNetBuffer 81 *=--------------------------------------------------------------------------=* 82 * Purpose: 83 * Ctor to instantiate from serialized data (BMessage). 84 * 85 * Input parameter: 86 * archive : Serialized object to instantiate from. 87 */ 88 BNetBuffer::BNetBuffer( BMessage* archive ) 89 : CTOR_INIT_LIST 90 { 91 const unsigned char* msgDataPtr; 92 ssize_t msgNBytes; 93 94 int32 dataSize; 95 int32 stackSize; 96 int32 capacity; 97 98 if ( archive->FindInt32( "bnbuff_datasize", &dataSize ) != B_OK ) 99 { 100 return; 101 } 102 103 if ( archive->FindInt32( "bnbuff_stacksize", &stackSize ) != B_OK ) 104 { 105 return; 106 } 107 108 if ( archive->FindInt32( "bnbuff_capacity", &capacity ) != B_OK ) 109 { 110 return; 111 } 112 113 if ( archive->FindData( "bnbuff_stack", B_RAW_TYPE, 114 ( const void** )&msgDataPtr, &msgNBytes ) != B_OK ) 115 { 116 return; 117 } 118 119 if ( capacity ) 120 { 121 if ( resize( capacity, true ) != B_OK ) 122 { 123 return; 124 } 125 126 memcpy( fData, msgDataPtr, stackSize ); 127 } 128 129 fDataSize = dataSize; 130 fStackSize = stackSize; 131 fCapacity = capacity; 132 133 fInit = B_OK; 134 } 135 136 137 /* ~BNetBuffer 138 *=--------------------------------------------------------------------------=* 139 * Purpose: 140 * Class dtor. 141 */ 142 BNetBuffer::~BNetBuffer( void ) 143 { 144 if ( fData != NULL ) 145 { 146 delete fData; 147 fData = NULL; 148 } 149 150 fDataSize = fStackSize = fCapacity = 0; 151 152 fInit = B_NO_INIT; 153 } 154 155 156 /* operator= 157 *=--------------------------------------------------------------------------=* 158 * Purpose: 159 * Class' assignment operator. 160 * 161 * Input parameter: 162 * refparam : Instance to assign from. 163 */ 164 BNetBuffer& BNetBuffer::operator=( const BNetBuffer& refparam ) 165 { 166 fInit = clone( refparam ); 167 168 return *this; 169 } 170 171 172 /* InitCheck 173 *=--------------------------------------------------------------------------=* 174 * Purpose: 175 * Determine whether or not this instance is properly initialized. 176 * 177 * Returns: 178 * B_OK if this instance is initialized, B_ERROR if not. 179 */ 180 status_t BNetBuffer::InitCheck( void ) 181 { 182 return ( fInit == B_OK ) ? B_OK : B_ERROR; 183 } 184 185 186 /* Archive 187 *=--------------------------------------------------------------------------=* 188 * Purpose: 189 * Serialize this instance into the passed BMessage parameter. 190 * 191 * Input parameter: 192 * deep : [ignored] default==true. 193 * 194 * Output parameter: 195 * into : BMessage object to serialize into. 196 * 197 * Returns: 198 * B_OK/BERROR on success/failure. Returns B_NO_INIT if instance not 199 * properly initialized. 200 */ 201 status_t BNetBuffer::Archive( BMessage* into, bool deep ) const 202 { 203 if ( fInit != B_OK ) 204 { 205 return B_NO_INIT; 206 } 207 208 if ( into->AddInt32( "bnbuff_datasize", fDataSize ) ) 209 { 210 return B_ERROR; 211 } 212 213 if ( into->AddInt32( "bnbuff_stacksize", fStackSize ) ) 214 { 215 return B_ERROR; 216 } 217 218 if ( into->AddInt32( "bnbuff_capacity", fCapacity ) ) 219 { 220 return B_ERROR; 221 } 222 223 if ( into->AddData( "bnbuff_stack", B_RAW_TYPE, fData, fStackSize ) != B_OK ) 224 //STM: Should we store the *whole* stack instead?......^^^^^^^^^^fCapacity 225 { 226 return B_ERROR; 227 } 228 229 return B_OK; 230 } 231 232 233 /* Instantiate 234 *=--------------------------------------------------------------------------=* 235 * Purpose: 236 * Un-serialize and instantiate from the passed BMessage parameter. 237 * 238 * Input parameter: 239 * archive : Archived BMessage object for (de)serialization. 240 * 241 * Returns: 242 * NULL if a BNetBuffer instance can not be initialized, otherwise 243 * a new BNetBuffer object instantiated from the BMessage parameter. 244 */ 245 BArchivable* BNetBuffer::Instantiate( BMessage* archive ) 246 { 247 if ( !validate_instantiation( archive, "BNetBuffer" ) ) 248 { 249 return NULL; 250 } 251 252 BNetBuffer* bnb = new BNetBuffer( archive ); 253 if ( bnb == NULL ) 254 { 255 return NULL; 256 } 257 258 if ( bnb->InitCheck( ) != B_OK ) 259 { 260 delete bnb; 261 return NULL; 262 } 263 264 return bnb; 265 } 266 267 268 /* AppendXXX 269 *=--------------------------------------------------------------------------=* 270 * Purpose: 271 * Append some data to this buffer (think PUSHing onto a FIFO stack). 272 * 273 * Returns: 274 * B_OK/B_ERROR for success/failure. B_NO_INIT if instance not properly 275 * initialized or stuck in some unknown state during construction. 276 * 277 * Remarks: 278 * * Where appropriate numeric data such as (u)int16, et al, are converted 279 * to network byte order during storage, no need to do this in advance. 280 */ 281 status_t BNetBuffer::AppendInt8( int8 Data ) 282 { 283 return dpush( B_INT8_TYPE, sizeof( int8 ), &Data ); 284 } 285 286 status_t BNetBuffer::AppendUint8( uint8 Data ) 287 { 288 return dpush( B_UINT8_TYPE, sizeof( uint8 ), &Data ); 289 } 290 291 status_t BNetBuffer::AppendInt16( int16 Data ) 292 { 293 int16 locData = B_HOST_TO_BENDIAN_INT16( Data ); 294 return dpush( B_INT16_TYPE, sizeof( int16 ), &locData ); 295 } 296 297 status_t BNetBuffer::AppendUint16( uint16 Data ) 298 { 299 uint16 locData = B_HOST_TO_BENDIAN_INT16( Data ); 300 return dpush( B_UINT16_TYPE, sizeof( uint16 ), &locData ); 301 } 302 303 status_t BNetBuffer::AppendInt32( int32 Data ) 304 { 305 int32 locData = B_HOST_TO_BENDIAN_INT32( Data ); 306 return dpush( B_INT32_TYPE, sizeof( int32 ), &locData ); 307 } 308 309 status_t BNetBuffer::AppendUint32( uint32 Data ) 310 { 311 uint32 locData = B_HOST_TO_BENDIAN_INT32( Data ); 312 return dpush( B_UINT32_TYPE, sizeof( uint32 ), &locData ); 313 } 314 315 status_t BNetBuffer::AppendInt64( int64 Data ) 316 { 317 int64 locData = B_HOST_TO_BENDIAN_INT64( Data ); 318 return dpush( B_INT64_TYPE, sizeof( int64 ), &locData ); 319 } 320 321 status_t BNetBuffer::AppendUint64( uint64 Data ) 322 { 323 uint64 locData = B_HOST_TO_BENDIAN_INT64( Data ); 324 return dpush( B_UINT64_TYPE, sizeof( uint64 ), &locData ); 325 } 326 327 status_t BNetBuffer::AppendFloat( float Data ) 328 { 329 return dpush( B_FLOAT_TYPE, sizeof( float ), &Data ); 330 } 331 332 status_t BNetBuffer::AppendDouble( double Data ) 333 { 334 return dpush( B_DOUBLE_TYPE, sizeof( double ), &Data ); 335 } 336 337 status_t BNetBuffer::AppendString( const char* Data ) 338 { 339 return dpush( B_STRING_TYPE, strlen( Data ), Data ); 340 } 341 342 status_t BNetBuffer::AppendData( const void* Data, size_t Length ) 343 { 344 return dpush( B_RAW_TYPE, Length, Data ); 345 } 346 347 status_t BNetBuffer::AppendMessage( const BMessage& Msg ) 348 { 349 status_t result; 350 ssize_t msgLen; 351 char* msgData; 352 353 msgLen = Msg.FlattenedSize( ); 354 if ( msgLen == 0 ) 355 { 356 //STM: It's possible, but SHOULD we store an empty BMessage? 357 //STM: Is an empty BMessage instance even legit in Be/OBOS? 358 return B_ERROR; 359 } 360 361 if ( ( msgData = new char[msgLen] ) == NULL ) 362 { 363 return B_ERROR; //STM: B_NO_MEM??? 364 } 365 366 // Don't get tripped on this, just trying to err on the side of caution. 367 result = B_ERROR; 368 369 if ( Msg.Flatten( msgData, msgLen ) == B_OK ) 370 { 371 result = dpush( B_MESSAGE_TYPE, msgLen, msgData ); 372 } 373 374 delete msgData; 375 return result; 376 } 377 378 379 /* RemoveXXXX 380 *=--------------------------------------------------------------------------=* 381 * Purpose: 382 * Remove some data from this buffer, think POPping from a FIFO stack. 383 * 384 * Returns: 385 * B_OK/B_ERROR for success/failure. B_NO_INIT if instance not properly 386 * initialized or stuck in some unknown state during construction. 387 * 388 * Remarks: 389 * Where appropriate numeric data such as (u)int16, et al, are converted 390 * from network byte order. No need to do this ipso post facto. 391 */ 392 status_t BNetBuffer::RemoveInt8( int8& Data ) 393 { 394 return dpop( B_INT8_TYPE, sizeof( int8 ), &Data ); 395 } 396 397 status_t BNetBuffer::RemoveUint8( uint8& Data ) 398 { 399 return dpop( B_UINT8_TYPE, sizeof( uint8 ), &Data ); 400 } 401 402 status_t BNetBuffer::RemoveInt16( int16& Data ) 403 { 404 // dpop will convert this bad boy from network to host byte order. 405 return dpop( B_INT16_TYPE, sizeof( int16 ), &Data ); 406 } 407 408 status_t BNetBuffer::RemoveUint16( uint16& Data ) 409 { 410 // dpop will convert this beast from network to host byte order. 411 return dpop( B_UINT16_TYPE, sizeof( uint16 ), &Data ); 412 } 413 414 status_t BNetBuffer::RemoveInt32( int32& Data ) 415 { 416 // dpop will convert this thang from network to host byte order. 417 return dpop( B_INT32_TYPE, sizeof( int32 ), &Data ); 418 } 419 420 status_t BNetBuffer::RemoveUint32( uint32& Data ) 421 { 422 // dpop will convert this variable from network to host byte order. 423 return dpop( B_UINT32_TYPE, sizeof( uint32 ), &Data ); 424 } 425 426 status_t BNetBuffer::RemoveInt64( int64& Data ) 427 { 428 // dpop will convert this bag-o-bits from network to host byte order. 429 return dpop( B_INT64_TYPE, sizeof( int64 ), &Data ); 430 } 431 432 status_t BNetBuffer::RemoveUint64( uint64& Data ) 433 { 434 // dpop will convert this construct from network to host byte order. 435 return dpop( B_UINT64_TYPE, sizeof( uint64 ), &Data ); 436 } 437 438 status_t BNetBuffer::RemoveFloat( float& Data ) 439 { 440 return dpop( B_FLOAT_TYPE, sizeof( float ), &Data ); 441 } 442 443 status_t BNetBuffer::RemoveDouble( double& Data ) 444 { 445 return dpop( B_DOUBLE_TYPE, sizeof( double ), &Data ); 446 } 447 448 status_t BNetBuffer::RemoveString( char* Data, size_t Length ) 449 { 450 return dpop( B_STRING_TYPE, Length, Data ); 451 } 452 453 status_t BNetBuffer::RemoveData( void* Data, size_t Length ) 454 { 455 return dpop( B_RAW_TYPE, Length, Data ); 456 } 457 458 status_t BNetBuffer::RemoveMessage( BMessage& message ) 459 { 460 status_t result; 461 int32 v; 462 unsigned char* stackPtr = fData; 463 char* msgData; 464 465 /* 466 * We have to cheat a little bit here and peek ahead of dpop so we can 467 * get at the size parameter. Perform basic checks along the way so we 468 * can make sure that we really get to the size parameter and not some 469 * bogus value. Redundant, but necessary. 470 */ 471 v = *( int32 * )stackPtr; 472 if ( v != DATA_START_MARKER ) 473 { 474 return B_ERROR; 475 } 476 477 stackPtr += sizeof( int32 ); 478 v = *( int32 * )stackPtr; 479 if ( v != B_MESSAGE_TYPE ) 480 { 481 return B_ERROR; 482 } 483 484 // Snarf the data size. 485 stackPtr += sizeof( int32 ); 486 v = *( int32 * )stackPtr; 487 488 if ( ( msgData = new char[v] ) == NULL ) 489 { 490 return B_ERROR; //STM: B_NO_MEM??? 491 } 492 493 if ( dpop( B_MESSAGE_TYPE, v, msgData ) != B_OK ) 494 { 495 delete msgData; 496 return B_ERROR; 497 } 498 499 result = message.Unflatten( msgData ); 500 delete msgData; 501 return result; 502 } 503 504 505 /* Data 506 *=--------------------------------------------------------------------------=* 507 * Purpose: 508 * Class accessor. 509 * 510 * Returns: 511 * Pointer to class' data suitable for those functions and methods that 512 * expect some kind of "generic" pointer. 513 * 514 * Remarks: 515 * * This is WEAK and WRONG, as it allows non-members to directly 516 * manipulate an instance's member data without the usual checks in 517 * place. At the very least the return value should be const. Ideally, 518 * this method should not exist. <author steps off soapbox> 519 */ 520 unsigned char* BNetBuffer::Data( void ) const 521 { 522 // Have I mentioned that this is a Really Bad Thing to do? 523 return fData; 524 // In case I missed it: returning a non-const pointer to our member data 525 // is not a good thing. Caveat emptor. 526 } 527 528 529 /* Size 530 *=--------------------------------------------------------------------------=* 531 * Purpose: 532 * Class accessor. 533 * 534 * Returns: 535 * How many bytes of data are contained. This *does not* include the 536 * overhead of the stack control variables (delineators and size). 537 */ 538 size_t BNetBuffer::Size( void ) const 539 { 540 return fDataSize; 541 } 542 543 544 /* BytesRemaining 545 *=--------------------------------------------------------------------------=* 546 * Purpose: 547 * Class accessor ...erm... sort of. 548 * 549 * Returns: 550 * How much capacity this instance has left to store data. 551 * 552 * Remarks: 553 * This method is essentially meaningless as the class' storage capacity 554 * will grow (or shrink) as necessary (that's an obfuscated way to say 555 * "dynamically re-allocated" boys and girls). Do not rely on this 556 * particular method in normal use as it refers to a moving target. 557 */ 558 size_t BNetBuffer::BytesRemaining( void ) const 559 { 560 return ( fCapacity - fStackSize ); 561 } 562 563 564 /* clone 565 *=--------------------------------------------------------------------------=* 566 * Purpose: 567 * Private copy helper method. 568 * 569 * Input parameter: 570 * RefParam: Instance to clone. 571 * 572 * Returns: 573 * status_t indicating success or point of failure (see resize()). 574 * B_NO_INIT if RefParam not properly initialized. 575 */ 576 status_t BNetBuffer::clone( const BNetBuffer& RefParam ) 577 { 578 if ( !RefParam.fInit ) 579 { 580 return B_NO_INIT; 581 } 582 583 if ( resize( RefParam.fCapacity, true ) != B_OK ) 584 { 585 return B_ERROR; 586 } 587 588 fDataSize = RefParam.fDataSize; 589 fStackSize = RefParam.fStackSize; 590 memcpy( fData, RefParam.fData, fStackSize ); 591 592 return B_OK; 593 } 594 595 596 /* dpop 597 *=--------------------------------------------------------------------------=* 598 * Purpose: 599 * Pop some data from our stack. 600 * 601 * Input parameters: 602 * Type : Expected data type for this record. 603 * Length : Expected data size for this record. 604 * 605 * Output parameter: 606 * Data : Recepticle for popped data. You are responsible for 607 * insuring that this is large enough to hold your 608 * intended data. If this parameter is NULL, you'll get 609 * back a B_ERROR. If the space allocated that this 610 * parameter points to is not sufficient to contain the 611 * intended data, you'll likely over-run something else 612 * in user-space and piss off a few folks in the process. 613 * 614 * Returns: 615 * B_OK/B_ERROR on success/failure. 616 * B_NO_INIT if this instance not properly initialized. 617 */ 618 status_t BNetBuffer::dpop( int32 Type, int32 Length, void* Data ) 619 { 620 if ( fInit != B_OK ) 621 { 622 return B_NO_INIT; 623 } 624 625 if ( Data == NULL ) 626 { 627 return B_ERROR; 628 } 629 630 unsigned char* stackPtr = fData; 631 unsigned char* userDataPtr; 632 int32 int32size = sizeof( int32 ); // <-- Performance: called a lot here. 633 int32 recordSize = ( ( int32size * 4 ) + Length ); 634 int32 tmp; 635 636 // Validate the start marker. 637 tmp = *( int32 * )stackPtr; 638 if ( tmp != (int32) DATA_START_MARKER ) 639 { 640 return B_ERROR; 641 } 642 643 // Validate the data type. 644 stackPtr += int32size; 645 tmp = *( int32 * )stackPtr; 646 if ( tmp != Type ) 647 { 648 return B_ERROR; 649 } 650 651 // Validate the data size. 652 stackPtr += int32size; 653 tmp = *( int32 * )stackPtr; 654 if ( tmp != Length ) 655 { 656 return B_ERROR; 657 } 658 659 // Stash a pointer to the contained user data, used when we really "pop." 660 stackPtr += int32size; 661 userDataPtr = stackPtr; 662 663 // Validate the end marker. 664 stackPtr += Length; 665 tmp = *( int32 * )stackPtr; 666 if ( tmp != (int32) DATA_END_MARKER ) 667 { 668 return B_ERROR; 669 } 670 671 // Point to the next entry in the stack. 672 stackPtr += int32size; 673 674 // Extract the contained data. 675 memcpy( Data, userDataPtr, Length ); 676 677 // Convert from network byte order if necessary. 678 switch ( Type ) 679 { 680 case B_INT16_TYPE: 681 case B_UINT16_TYPE: 682 *( uint16 * )Data = B_BENDIAN_TO_HOST_INT16( *( uint16 * )Data ); 683 break; 684 685 case B_INT32_TYPE: 686 case B_UINT32_TYPE: 687 *( uint32 * )Data = B_BENDIAN_TO_HOST_INT32( *( uint32 * )Data ); 688 break; 689 690 case B_INT64_TYPE: 691 case B_UINT64_TYPE: 692 *( uint64 * )Data = B_BENDIAN_TO_HOST_INT64( *( uint64 * )Data ); 693 break; 694 695 default: 696 break; 697 } 698 699 // Condense the stack. 700 fStackSize -= recordSize; 701 memmove( fData, stackPtr, fStackSize ); 702 703 // Zero out the unused area of the stack where we memmove'd from. 704 memset( &fData[fStackSize], 0, ( fCapacity - fStackSize ) ); 705 706 // Update the extents. 707 fCapacity += recordSize; 708 fDataSize -= Length; 709 710 return B_OK; 711 } 712 713 714 /* dpush 715 *=--------------------------------------------------------------------------=* 716 * Purpose: 717 * Push some data onto our buffer. 718 * 719 * Input parameters: 720 * Type : Data type for this record. 721 * Length : Data length for this record. 722 * Data : Pointer to data to store. NO-OP (B_ERROR) if NULL. 723 * 724 * Returns: 725 * B_OK/B_ERROR on success/failure. 726 * B_NO_INIT if this instance not properly initialized. 727 * 728 * Remarks: 729 * * No need to worry about host-to-network byte ordering conversion -- 730 * since this is a /private/ helper said conversion, where applicable, 731 * takes place in our caller (see AddIntXX if you haven't already passed 732 * them on your way down to this humble helper). 733 */ 734 status_t BNetBuffer::dpush( int32 Type, int32 Length, const void* Data ) 735 { 736 if ( fInit != B_OK ) 737 { 738 return B_NO_INIT; 739 } 740 741 if ( Data == NULL ) 742 { 743 return B_ERROR; 744 } 745 746 int32 int32size = sizeof( int32 ); // <--Performance: called a lot here. 747 int32 recordSize = ( ( int32size * 4 ) + Length ); 748 749 if ( resize( fCapacity + recordSize ) != B_OK ) 750 { 751 return B_ERROR; 752 } 753 754 unsigned char* stackPtr = &fData[fStackSize]; 755 *( int32 * )stackPtr = DATA_START_MARKER; 756 757 stackPtr += int32size; 758 *( int32 * )stackPtr = Type; 759 760 stackPtr += int32size; 761 *( int32 * )stackPtr = Length; 762 763 stackPtr += int32size; 764 memcpy( stackPtr, Data, Length ); 765 766 stackPtr += Length; 767 *( int32 * )stackPtr = DATA_END_MARKER; 768 769 // Groovy! All stored, dot our t's and cross our i's. 770 fDataSize += Length; 771 fStackSize += recordSize; 772 773 return B_OK; 774 } 775 776 777 /* resize 778 *=--------------------------------------------------------------------------=* 779 * Purpose: 780 * Grow the internal data buffer to accommodate the requested size. 781 * 782 * //STM: What about shrinking the buffer to conserve resources? 783 * 784 * Input parameter: 785 * NewSize : New size of data buffer. Duh. 786 * RegenStack : If true, do not try to preserve the existing stack. 787 * Default is false (preserve existing data). 788 * 789 * Returns: 790 * B_OK: Success. 791 * B_NO_MEMORY: if we cannot allocate memory for the data buffer. 792 * 793 * Remarks: 794 * * In keeping with the "contract programming" development model: this is 795 * a "safe copy" method in that the class' existing member data will not 796 * be disturbed in the event of failure. When our caller gets back a 797 * success status (B_OK), said caller is guaranteed that all is well. 798 * Laterally, in the event this method returns failure, the caller is 799 * guaranteed that the class' existing member data is left untouched, 800 * thereby preserving the existing instance's integrity. 801 * 802 * * Buffer size is adjusted on a 16-byte granularity to keep from beating 803 * the bleep out of the memory pool (can you say "fragmentation" boys and 804 * girls?). To tweak the granularity, change the GRANULARITY token at the 805 * beginning of this method. For best results, GRANULARITY should be a 806 * power of two, thankyouverymuch. 807 * 808 * * 'RegenStack' and its intented behavior is a bit of a double-negative. 809 * May have to change this to eliminate said double negative if it proves 810 * to be too confusing. 811 */ 812 status_t BNetBuffer::resize( int32 NewSize, bool RegenStack ) 813 { 814 #define GRANULARITY 16 815 816 unsigned char* newData; 817 int32 newCapacity; 818 819 newCapacity = ( ( ( NewSize / GRANULARITY ) + 1 ) * GRANULARITY ); 820 821 // Don't waste cycles or thrash the memory pool if we don't need to... 822 if ( newCapacity <= fCapacity ) 823 { 824 return B_OK; 825 } 826 827 /* STM: If we decide to shrink as well as grow, then replace above with: 828 if ( newCapacity == fCapacity ) 829 { 830 return B_OK; 831 } 832 */ 833 834 newData = new unsigned char[newCapacity]; 835 if ( newData == NULL ) 836 { 837 return B_NO_MEMORY; 838 } 839 840 // Paranoid? Pffffsh. You bet. :-) 841 memset( newData, 0, newCapacity ); 842 843 if ( fData != NULL ) 844 { 845 if ( !RegenStack ) 846 { 847 memcpy( newData, fData, fStackSize ); 848 } 849 850 delete fData; 851 } 852 853 fData = newData; 854 fCapacity = newCapacity; 855 856 return B_OK; 857 858 #undef GRANULARITY 859 } 860 861 862 /* Reserved methods, for future evolution */ 863 864 void BNetBuffer::_ReservedBNetBufferFBCCruft1() 865 { 866 } 867 868 void BNetBuffer::_ReservedBNetBufferFBCCruft2() 869 { 870 } 871 872 void BNetBuffer::_ReservedBNetBufferFBCCruft3() 873 { 874 } 875 876 void BNetBuffer::_ReservedBNetBufferFBCCruft4() 877 { 878 } 879 880 void BNetBuffer::_ReservedBNetBufferFBCCruft5() 881 { 882 } 883 884 void BNetBuffer::_ReservedBNetBufferFBCCruft6() 885 { 886 } 887 888 889 /*=------------------------------------------------------------------- End -=*/ 890