xref: /haiku/src/kits/network/libnetapi/NetBuffer.cpp (revision 302f62604763c95777d6d04cca456e876f471c4f)
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