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