symport/e32/euser/cbase/ub_buf.cpp
changeset 1 0a7b44b10206
child 2 806186ab5e14
equal deleted inserted replaced
0:c55016431358 1:0a7b44b10206
       
     1 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Symbian Foundation License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32\euser\cbase\ub_buf.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "ub_std.h"
       
    19 
       
    20 class TBufSegLink : public TDblQueLink
       
    21 	{
       
    22 public:
       
    23 	inline TBufSegLink() : iLen(0) {}
       
    24 	inline TBufSegLink *Next() const {return((TBufSegLink *)iNext);}
       
    25 	inline TBufSegLink *Prev() const {return((TBufSegLink *)iPrev);}
       
    26 public:
       
    27 	TInt iLen;
       
    28 	};
       
    29 
       
    30 EXPORT_C CBufBase::CBufBase(TInt anExpandSize)
       
    31 //
       
    32 // Constructor
       
    33 //
       
    34 /**
       
    35 @internalComponent
       
    36 */
       
    37 	{
       
    38 
       
    39 	__ASSERT_ALWAYS(anExpandSize>=0,Panic(EBufExpandSizeNegative));
       
    40 //	iSize=0;
       
    41 	iExpandSize=anExpandSize;
       
    42 	}
       
    43 
       
    44 EXPORT_C CBufBase::~CBufBase()
       
    45 /**
       
    46 Destructor
       
    47 */
       
    48 	{
       
    49 	}
       
    50 
       
    51 EXPORT_C void CBufBase::Reset()
       
    52 /**
       
    53 Deletes all data in the buffer.
       
    54 
       
    55 Its behaviour is the same as calling Delete(0,Size()). 
       
    56 The buffer is compressed before the function returns.
       
    57 */
       
    58 	{
       
    59 
       
    60 	if (iSize)
       
    61 		Delete(0,iSize);
       
    62 	Compress();
       
    63 	}
       
    64 
       
    65 EXPORT_C void CBufBase::Read(TInt aPos,TDes8 &aDes) const
       
    66 //
       
    67 // Read up to aDes.MaxLength() bytes.
       
    68 //
       
    69 /**
       
    70 Reads data from the buffer into a descriptor.
       
    71 
       
    72 Data, starting at the specified buffer position is written to the descriptor, 
       
    73 filling the descriptor.
       
    74 
       
    75 @param aPos Buffer position from which data is read: must be in range zero 
       
    76             to Size(). 
       
    77 @param aDes On return, contains the data read from the buffer; its MaxLength() 
       
    78             specifies the amount of data to be read.
       
    79 */
       
    80 	{
       
    81 
       
    82 	Read(aPos,aDes,aDes.MaxLength());
       
    83 	}
       
    84 
       
    85 EXPORT_C void CBufBase::Read(TInt aPos,TDes8 &aDes,TInt aLength) const
       
    86 /**
       
    87 Reads the specified number of bytes of data from the buffer into a descriptor.
       
    88 
       
    89 @param aPos    Buffer position from which data is read: must be in range zero 
       
    90                to (Size() minus the length of the data to be read). 
       
    91 @param aDes    On return, contains data read from the buffer.
       
    92 @param aLength The length of the data to be read.
       
    93 */
       
    94 	{
       
    95 
       
    96 	aDes.SetLength(aLength);
       
    97 	Read(aPos,(TAny *)aDes.Ptr(),aLength);
       
    98 	}
       
    99 
       
   100 EXPORT_C void CBufBase::Read(TInt aPos,TAny *aPtr,TInt aLength) const
       
   101 /**
       
   102 Reads the specified number of bytes of data from the buffer into a specified 
       
   103 address.
       
   104 
       
   105 @param aPos    Buffer position from which data is read: must be in range zero 
       
   106                to (Size() minus the length of the data to be read). 
       
   107 @param aPtr    The address into which the data should be read.
       
   108 @param aLength The length of the data to be read.
       
   109 */
       
   110 	{
       
   111 
       
   112 	if (aLength==0)
       
   113 		return;
       
   114 	__ASSERT_ALWAYS(aLength>0,Panic(EBufReadLengthNegative));
       
   115 	__ASSERT_ALWAYS((aPos+aLength)<=iSize,Panic(EBufReadBeyondEnd));
       
   116 	TUint8 *pT=(TUint8 *)aPtr;
       
   117 	while (aLength)
       
   118 		{
       
   119 		TPtr8 p=((CBufBase *)this)->Ptr(aPos);
       
   120 		TInt s=Min(p.Length(),aLength);
       
   121 		pT=Mem::Copy(pT,p.Ptr(),s);
       
   122 		aLength-=s;
       
   123 		aPos+=s;
       
   124 		}
       
   125 	}
       
   126 
       
   127 EXPORT_C void CBufBase::Write(TInt aPos,const TDesC8 &aDes)
       
   128 //
       
   129 // Write aDes.Length() characters to the buffer. Does not cause any expansion.
       
   130 //
       
   131 /**
       
   132 Writes data from a descriptor to the buffer.
       
   133 
       
   134 The data in the descriptor overwrites the data in the buffer from the insertion 
       
   135 point onwards.
       
   136 
       
   137 No new space is allocated; this function cannot fail (provided the parameters 
       
   138 are specified within the bounds of the buffer and descriptor).
       
   139 
       
   140 No shuffling occurs; new data is written to the memory locations occupied 
       
   141 by the data it overwrites.
       
   142 
       
   143 @param aPos Buffer position at which data will begin to be written; must be 
       
   144             in range zero to (Size() minus the length of the data
       
   145             to be written). 
       
   146 @param aDes Contains the data to be written. The length of data to be written
       
   147             is the descriptor length.
       
   148 */
       
   149 	{
       
   150 
       
   151 	Write(aPos,aDes.Ptr(),aDes.Length());
       
   152 	}
       
   153 
       
   154 EXPORT_C void CBufBase::Write(TInt aPos,const TDesC8 &aDes,TInt aLength)
       
   155 //
       
   156 // Write aDes.Length() characters to the buffer. Does not cause any expansion.
       
   157 //
       
   158 /**
       
   159 Writes the specified number of bytes of data from a descriptor to the buffer.
       
   160 
       
   161 The data in the descriptor overwrites the data in the buffer from the insertion 
       
   162 point onwards.
       
   163 
       
   164 No new space is allocated; this function cannot fail (provided the parameters 
       
   165 are specified within the bounds of the buffer and descriptor).
       
   166 
       
   167 No shuffling occurs; new data is written to the memory locations occupied 
       
   168 by the data it overwrites.
       
   169 
       
   170 @param aPos    Buffer position at which data will begin to be written; must be 
       
   171                in range zero to (Size() minus the length of the data to
       
   172                be written). 
       
   173 @param aDes    Contains the data to be written.
       
   174 @param aLength The length of the data to be written.
       
   175 */
       
   176 	{
       
   177 
       
   178 	Write(aPos,aDes.Ptr(),aLength);
       
   179 	}
       
   180 
       
   181 EXPORT_C void CBufBase::Write(TInt aPos,const TAny *aPtr,TInt aLength)
       
   182 /**
       
   183 Writes the specified number of bytes of data from the specified address to the 
       
   184 buffer.
       
   185 
       
   186 The data in the buffer is overwritten from the insertion point onwards.
       
   187 
       
   188 No new space is allocated; this function cannot fail (provided the parameters 
       
   189 are specified within the bounds of the buffer and descriptor).
       
   190 
       
   191 No shuffling occurs: new data is written to the memory locations occupied 
       
   192 by the data it overwrites.
       
   193 
       
   194 @param aPos    Buffer position at which data will begin to be written; must be 
       
   195                in range zero to (Size() minus the length of the data to
       
   196                be written). 
       
   197 @param aPtr    The address of the data to be written.
       
   198 @param aLength The length of the data to be written.
       
   199 
       
   200 @panic E32USER-CBase 7, if aLength is not positive
       
   201 @panic E32USER-CBase 5, if aPos + aLength is greater than the number of
       
   202                         data bytes in the buffer, i.e. if the target appears
       
   203                         to be outside the buffer.
       
   204 */
       
   205 	{
       
   206 
       
   207 	if (aLength==0)
       
   208 		return;
       
   209 	__ASSERT_ALWAYS(aLength>0,Panic(EBufWriteLengthNegative));
       
   210 	__ASSERT_ALWAYS((aPos+aLength)<=iSize,Panic(EBufWriteBeyondEnd));
       
   211 	const TUint8 *pS=(const TUint8 *)aPtr;
       
   212 	while (aLength)
       
   213 		{
       
   214 		TPtr8 p=Ptr(aPos);
       
   215 		TInt s=Min(p.Length(),aLength);
       
   216 		Mem::Copy((TAny *)p.Ptr(),pS,s);
       
   217 		pS+=s;
       
   218 		aLength-=s;
       
   219 		aPos+=s;
       
   220 		}
       
   221 	}
       
   222 
       
   223 EXPORT_C void CBufBase::InsertL(TInt aPos,const TDesC8 &aDes)
       
   224 //
       
   225 // Insert aDes.Length() bytes into the buffer.
       
   226 //
       
   227 /**
       
   228 Inserts data into the buffer.
       
   229 
       
   230 Data at and beyond the insertion position is moved to make way for the inserted 
       
   231 data. Data before the insertion position remains in place.
       
   232 
       
   233 Notes:
       
   234 
       
   235 1. Insertion may require more buffer space to be allocated.
       
   236 
       
   237 2. In the case of flat buffers, the buffer is extended by a ReAllocL() of the 
       
   238    buffer's heap cell, to the smallest multiple of the granularity that will 
       
   239    contain the data required. If this reallocation fails, the insertion is
       
   240    impossible and a leave occurs.
       
   241 
       
   242 3. In the case of segmented buffers, a reallocation is performed if the segment 
       
   243    containing the insertion position has insufficient space, and
       
   244    immediately-neighbouring segments cannot be used to contain the new data.
       
   245    As many new segments as are necessary to contain the inserted data are
       
   246    allocated. Each new segment's length is the buffer's granularity.
       
   247    If extension or new allocation fails, a leave occurs.
       
   248 
       
   249 4. Insertion may also require data to be shuffled. In the case of flat buffers, 
       
   250    data beyond the insertion point is shuffled up to create a gap; the new data 
       
   251    is then inserted into this gap. In the case of segmented buffers, shuffling 
       
   252    is minimised by inserting the new data into newly-allocated buffers, and
       
   253    shuffling only immediately-neighbouring buffers if possible. This may result
       
   254    in some wastage of space, but is much more time-efficient for large amounts
       
   255    of data.
       
   256 
       
   257 @param aPos Buffer position before which the data will be inserted; must be 
       
   258             in range zero to Size().
       
   259 @param aDes The data to be inserted; the length of the data is the descriptor
       
   260             length.
       
   261 
       
   262 @leave KErrNoMemory If the insertion requires a bigger buffer, and the
       
   263        necessary allocation or re-allocation fails.
       
   264 */
       
   265 	{
       
   266 
       
   267 	InsertL(aPos,aDes.Ptr(),aDes.Length());
       
   268 	}
       
   269 
       
   270 EXPORT_C void CBufBase::InsertL(TInt aPos,const TDesC8 &aDes,TInt aLength)
       
   271 //
       
   272 // Insert aLength bytes into the buffer.
       
   273 //
       
   274 /**
       
   275 Inserts the specified number of bytes of data from a descriptor into
       
   276 the buffer.
       
   277 
       
   278 aLength bytes of data from aDes are inserted into the buffer at aPos. Data at
       
   279 and beyond the insertion position is moved to make way for the inserted data. 
       
   280 Data before the insertion position remains in place.
       
   281 
       
   282 Notes:
       
   283 
       
   284 1. Insertion may require more buffer space to be allocated.
       
   285 
       
   286 2. In the case of flat buffers, the buffer is extended by a ReAllocL() of the 
       
   287    buffer's heap cell, to the smallest multiple of the granularity that will 
       
   288    contain the data required. If this reallocation fails, the insertion is
       
   289    impossible and a leave occurs.
       
   290 
       
   291 3. In the case of segmented buffers, a reallocation is performed if the segment 
       
   292    containing the insertion position has insufficient space, and
       
   293    immediately-neighbouring segments cannot be used to contain the new data.
       
   294    As many new segments as are necessary to contain the inserted data are
       
   295    allocated. Each new segment's length is the buffer's granularity.
       
   296    If extension or new allocation fails, a leave occurs.
       
   297 
       
   298 4. Insertion may also require data to be shuffled. In the case of flat buffers, 
       
   299    data beyond the insertion point is shuffled up to create a gap: the new data 
       
   300    is then inserted into this gap. In the case of segmented buffers, shuffling 
       
   301    is minimised by inserting the new data into newly-allocated buffers,
       
   302    and shuffling  only immediately-neighbouring buffers if possible.
       
   303    This may result in some  wastage of space, but is much more time-efficient
       
   304    for large amounts of data.
       
   305    
       
   306 @param aPos    Buffer position before which the data will be inserted; must be 
       
   307                in range zero to Size().
       
   308 @param aDes    The data to be inserted.
       
   309 @param aLength The length of data to be inserted. 
       
   310 
       
   311 @leave KErrNoMemory If the insertion requires a bigger buffer, and the
       
   312        necessary allocation or re-allocation fails.
       
   313 */
       
   314 	{
       
   315 
       
   316 	InsertL(aPos,aDes.Ptr(),aLength);
       
   317 	}
       
   318 
       
   319 EXPORT_C void CBufBase::InsertL(TInt aPos,const TAny *aPtr,TInt aLength)
       
   320 /**
       
   321 Inserts bytes of data from the specified address into the buffer.
       
   322 
       
   323 Inserts aLength bytes of data found at address aPtr into the buffer at aPos. 
       
   324 Data at and beyond the insertion position is moved to make way for the inserted 
       
   325 data. Data before the insertion position remains in place.
       
   326 
       
   327 Notes:
       
   328 
       
   329 1. Insertion may require more buffer space to be allocated.
       
   330 
       
   331 2. In the case of flat buffers, the buffer is extended by a ReAllocL() of the 
       
   332    buffer's heap cell, to the smallest multiple of the granularity that will 
       
   333    contain the data required. If this reallocation fails, the insertion is
       
   334    impossible and a leave occurs.
       
   335 
       
   336 2. In the case of segmented buffers, a reallocation is performed if the segment 
       
   337    containing the insertion position has insufficient space, and
       
   338    immediately-neighbouring segments cannot be used to contain the new data.
       
   339    As many new segments as are necessary to contain the inserted data are
       
   340    allocated. Each new segment's length is the buffer's granularity.
       
   341    If extension or new allocation fails, a leave occurs.
       
   342 
       
   343 4. Insertion may also require data to be shuffled. In the case of flat buffers, 
       
   344    data beyond the insertion point is shuffled up to create a gap: the new data 
       
   345    is then inserted into this gap. In the case of segmented buffers, shuffling 
       
   346    is minimised by inserting the new data into newly-allocated buffers, and
       
   347    shuffling only immediately-neighbouring buffers if possible. This may result
       
   348    in some wastage of space, but is much more time-efficient for large amounts
       
   349    of data.
       
   350 
       
   351 @param aPos    Buffer position before which the data will be inserted: must be 
       
   352                in range zero to Size().
       
   353 @param aPtr    The address of the data to be inserted. 
       
   354 @param aLength The length of the data to be inserted.
       
   355  
       
   356 @leave KErrNoMemory If the insertion requires a bigger buffer, and the
       
   357        necessary allocation or re-allocation fails.
       
   358 */
       
   359 	{
       
   360 
       
   361 	if (aLength==0)
       
   362 		return;
       
   363 	__ASSERT_ALWAYS(aLength>0,Panic(EBufInsertLengthNegative));
       
   364 	__ASSERT_ALWAYS(aPtr,Panic(EBufInsertBadPtr));
       
   365 	DoInsertL(aPos,aPtr,aLength);
       
   366 	}
       
   367 
       
   368 EXPORT_C void CBufBase::ExpandL(TInt aPos,TInt aLength)
       
   369 /**
       
   370 Inserts an uninitialised region into the buffer.
       
   371 
       
   372 Data at and beyond the insertion position is moved to make way for the inserted
       
   373 region. Data before the insertion position remains in place.
       
   374 
       
   375 Note:
       
   376 
       
   377 1. The inserted region is not initialised. After using ExpandL(), you should 
       
   378    then use a series of Write()s to fill this region with data.
       
   379 
       
   380 2. Use ExpandL() followed by a series of Write()s when you know the amount of 
       
   381    data to be inserted, in advance. It is more efficient than a series of
       
   382    InsertL()s. In addition, once the result of the ExpandL() has been checked,
       
   383    it is guaranteed that the Write()s do not leave, which can sometimes be
       
   384    useful.
       
   385 
       
   386 @param aPos    Buffer position before which the region will be inserted; must 
       
   387                be in range zero to Size(). 
       
   388 @param aLength The length of the region to be inserted.
       
   389 */
       
   390 	{
       
   391 
       
   392 	if (aLength==0)
       
   393 		return;
       
   394 	__ASSERT_ALWAYS(aLength>0,Panic(EBufInsertLengthNegative));
       
   395 	DoInsertL(aPos,NULL,aLength);
       
   396 	}
       
   397 
       
   398 EXPORT_C void CBufBase::ResizeL(TInt aSize)
       
   399 /**
       
   400 Re-sizes the buffer to the specified size.
       
   401 
       
   402 The new size can be larger or smaller than the existing size.
       
   403 
       
   404 If the new size is larger than the existing size, the buffer is expanded by 
       
   405 adding uninitialised data to the end of it.
       
   406 
       
   407 If the new size is smaller than the existing size, the buffer is reduced; 
       
   408 any data at the end of the buffer is lost.
       
   409 
       
   410 Notes:
       
   411 
       
   412 1. If the new size is larger than the existing size, the function is equivalent 
       
   413    to Delete(aSize,Size()-aSize).
       
   414 
       
   415 2. If the new size is smaller than the existing size, the function is equivalent 
       
   416    to ExpandL((Size(),aSize-Size()).
       
   417 
       
   418 3. The motivations for using ResizeL() are the same as those for using Delete() 
       
   419    and ExpandL().
       
   420 
       
   421 @param aSize The new size of the buffer; this value must be greater than or 
       
   422              equal to zero.
       
   423 */
       
   424 	{
       
   425 
       
   426 	TInt excess=iSize-aSize;
       
   427 	if (excess>0)
       
   428 		Delete(aSize,excess);
       
   429 	else
       
   430 		ExpandL(iSize,-excess);
       
   431 	}
       
   432 
       
   433 EXPORT_C CBufFlat *CBufFlat::NewL(TInt anExpandSize)
       
   434 /**
       
   435 Allocates and constructs a flat buffer.
       
   436 
       
   437 If there is insufficient memory available to allocate the flat buffer, the 
       
   438 function leaves.
       
   439 
       
   440 @param anExpandSize The granularity of buffer expansion. Additional space, 
       
   441                     when required, is always allocated in multiples of
       
   442                     this number. Note: although a value of zero is permitted
       
   443                     by this interface, it has no meaning, and risks raising
       
   444                     panics later during execution. We suggest that you pass
       
   445                     a positive value.
       
   446                                         
       
   447 @return A pointer to the flat buffer object.
       
   448 
       
   449 @panic E32USER-CBase 3 if the granularity is negative.
       
   450 */
       
   451 	{
       
   452 
       
   453 	return(new(ELeave) CBufFlat(anExpandSize));
       
   454 	}
       
   455 
       
   456 EXPORT_C CBufFlat::CBufFlat(TInt anExpandSize)
       
   457 //
       
   458 // Constructor
       
   459 //
       
   460 /**
       
   461 @internalComponent
       
   462 */
       
   463 	: CBufBase(anExpandSize)
       
   464 	{
       
   465 
       
   466 //	iMaxSize=0;
       
   467 //	iPtr=NULL;
       
   468 	}
       
   469 
       
   470 EXPORT_C CBufFlat::~CBufFlat()
       
   471 /** 
       
   472 Destructor.
       
   473 
       
   474 Frees all resources owned by the object, prior to its destruction.
       
   475 Specifically, it frees the allocated cell used as a buffer.
       
   476 */
       
   477 	{
       
   478 
       
   479 	User::Free(iPtr);
       
   480 	}
       
   481 
       
   482 EXPORT_C void CBufFlat::Compress()
       
   483 /**
       
   484 Compresses the buffer so as to occupy minimal space.
       
   485 
       
   486 This frees any unused memory at the end of the buffer.
       
   487 
       
   488 @see CBufBase::Compress
       
   489 */
       
   490 	{
       
   491 
       
   492 	SetReserveL(iSize);
       
   493 	}
       
   494 
       
   495 EXPORT_C void CBufFlat::SetReserveL(TInt aSize)
       
   496 /**
       
   497 Specifies a minimum amount of space which the flat buffer should occupy.
       
   498 
       
   499 If the required size is zero, the heap cell is deleted. If it is different 
       
   500 from the current size, the heap cell is rellocated accordingly.
       
   501 
       
   502 @param aSize The size of the buffer required. If there is no data in the
       
   503              buffer, i.e. Size() returns zero, then this value 
       
   504              can be zero, which causes the buffer's allocated heap cell
       
   505              to be deleted.
       
   506 
       
   507 @panic E32USER-CBase 10, if aSize is negative.
       
   508 @panic E32USER-CBase 11, if there is data in the buffer, and aSize is less than
       
   509        the value returned by Size().
       
   510 */
       
   511 	{
       
   512 
       
   513 	__ASSERT_ALWAYS(aSize>=0,Panic(EBufFlatReserveNegative));
       
   514 	__ASSERT_ALWAYS(aSize>=iSize,Panic(EBufFlatReserveSetTooSmall));
       
   515     if (!aSize)
       
   516         {
       
   517         User::Free(iPtr);
       
   518         iPtr=NULL;
       
   519         }
       
   520     else
       
   521         iPtr=(TUint8 *)User::ReAllocL(iPtr,aSize);
       
   522     iMaxSize=aSize;
       
   523 	}
       
   524 
       
   525 EXPORT_C void CBufFlat::DoInsertL(TInt aPos,const TAny *aPtr,TInt aLength)
       
   526 //
       
   527 // Insert into the buffer. Can cause expansion.
       
   528 //
       
   529 	{
       
   530 
       
   531 	__ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange));
       
   532 	TInt len=iSize+aLength;
       
   533 	if (len>iMaxSize)
       
   534 		{
       
   535 		TInt r=len-iMaxSize;
       
   536 		r=((r/iExpandSize)+1)*iExpandSize;
       
   537 		SetReserveL(iMaxSize+r);
       
   538 		}
       
   539 	Mem::Copy(iPtr+aPos+aLength,iPtr+aPos,iSize-aPos);
       
   540 	if (aPtr)
       
   541 		Mem::Copy(iPtr+aPos,aPtr,aLength);
       
   542 	iSize+=aLength;
       
   543 	}
       
   544 
       
   545 EXPORT_C void CBufFlat::Delete(TInt aPos,TInt aLength)
       
   546 /**
       
   547 Deletes data from the buffer.
       
   548 
       
   549 During deletion, any data beyond the deleted data is shuffled up so that
       
   550 the buffer contents are contiguous. No memory is freed.
       
   551 
       
   552 @param aPos    Buffer position where the deletion will begin; must be in the 
       
   553                range zero to (Size() minus the length of the data
       
   554                to be deleted). 
       
   555 @param aLength The number of bytes to be deleted.
       
   556 
       
   557 @panic E32USER-CBase 12, if aPos is negative or is greater than the
       
   558        current size of the buffer.
       
   559 @panic E32USER-CBase 13, if aPos + aLength is greater than the
       
   560        current size of the buffer.
       
   561        
       
   562 @see CBufBase::Delete
       
   563 */
       
   564 	{
       
   565 
       
   566 	__ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange));
       
   567 	__ASSERT_ALWAYS((aPos+aLength)<=iSize,Panic(EBufFlatDeleteBeyondEnd));
       
   568 	Mem::Copy(iPtr+aPos,iPtr+aPos+aLength,iSize-aLength-aPos);
       
   569 	iSize-=aLength;
       
   570 	}
       
   571 
       
   572 EXPORT_C TPtr8 CBufFlat::Ptr(TInt aPos)
       
   573 /**
       
   574 Gets a pointer descriptor to represent the data starting at the specified
       
   575 data byte through to the end of the contiguous region containing that byte.
       
   576 
       
   577 Calculation of the pointer and length involves only a few machine instructions
       
   578 and is independent of the data contained in the buffer.
       
   579 
       
   580 @param aPos Buffer position: must be in range zero to Size().
       
   581 	 
       
   582 @return Descriptor representing the data starting at aPos to the end of
       
   583         the buffer.      	
       
   584 */
       
   585 	{
       
   586 
       
   587 	__ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange));
       
   588 	TInt len=iSize-aPos;
       
   589 	return(TPtr8(iPtr+aPos,len,len));
       
   590 	}
       
   591 
       
   592 EXPORT_C TPtr8 CBufFlat::BackPtr(TInt aPos)
       
   593 //
       
   594 // Return a pointer to the buffer which has the maximum amount of data
       
   595 // before aPos, and the amount of data remaining.  
       
   596 //
       
   597 /**
       
   598 Gets a pointer descriptor to represent the data starting at the beginning
       
   599 of the contiguous region containing that byte through to the byte immediately
       
   600 preceding the specified byte.
       
   601 
       
   602 The descriptor always points to the beginning of the buffer containing
       
   603 the specified byte. Calculation of the pointer and length involves only a few
       
   604 machine instructions and is independent of the data contained in the buffer.
       
   605 
       
   606 @param aPos Buffer position: must be in range zero to Size().
       
   607 
       
   608 @return Descriptor representing the back contiguous region. 
       
   609 
       
   610 @see CBufBase::BackPtr
       
   611 */
       
   612 	{
       
   613 
       
   614 	__ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange));
       
   615 	return(TPtr8(iPtr,aPos,aPos));
       
   616 	}
       
   617 
       
   618 void CBufSeg::InsertIntoSegment(TBufSegLink *aSeg,TInt anOffset,const TAny *aPtr,TInt aLength)
       
   619 //
       
   620 // Insert into the segment.
       
   621 //
       
   622 	{
       
   623 
       
   624     if (aLength)
       
   625         {
       
   626         TUint8 *pS=((TUint8 *)(aSeg+1))+anOffset;
       
   627         Mem::Copy(pS+aLength,pS,aSeg->iLen-anOffset);
       
   628 		if (aPtr)
       
   629 			Mem::Copy(pS,aPtr,aLength);
       
   630         aSeg->iLen+=aLength;
       
   631         }
       
   632 	}
       
   633 
       
   634 void CBufSeg::DeleteFromSegment(TBufSegLink *aSeg,TInt anOffset,TInt aLength)
       
   635 //
       
   636 // Delete from the segment.
       
   637 //
       
   638 	{
       
   639 
       
   640     if (aLength)
       
   641         {
       
   642         TUint8 *pS=((TUint8 *)(aSeg+1))+anOffset;
       
   643         Mem::Copy(pS,pS+aLength,aSeg->iLen-anOffset-aLength);
       
   644         aSeg->iLen-=aLength;
       
   645         }
       
   646 	}
       
   647 
       
   648 void CBufSeg::FreeSegment(TBufSegLink *aSeg)
       
   649 //
       
   650 // Free an entire segment.
       
   651 //
       
   652 	{
       
   653 
       
   654     aSeg->Deque();
       
   655     User::Free(aSeg);
       
   656 	}
       
   657 
       
   658 void CBufSeg::SetSBO(TInt aPos)
       
   659 //
       
   660 // Set a segment-base-offset struct (SBO) to a new pos.
       
   661 // If the initial psbo->seg is not NULL, it assumes that it is a valid
       
   662 // SBO for a different position and counts relative to the initial SBO
       
   663 // to set the desired position. If the initial psbo->seg is NULL, it starts
       
   664 // scanning from the beginning ie pos=0.
       
   665 // When the position is between segments A and B, there are two equivalent
       
   666 // positions: (1) at the beginning of B and (2) at the end of A.
       
   667 // Option (1) is suitable for referencing the data and deleting.
       
   668 // Option (2) is best for insertion when A is not full.
       
   669 // This function uses option (1) and will always set the SBO to the
       
   670 // beginning of the next segment. It does however set to the end of the
       
   671 // last segment when pos is equal to the number of bytes in the buffer.
       
   672 //
       
   673 	{
       
   674 
       
   675     __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufSegPosOutOfRange));
       
   676     if (aPos==iSize)
       
   677         { // Positioning to end is treated as a special case
       
   678         iSeg=0;
       
   679         if (iSize)
       
   680             iBase=aPos-(iOffset=(iSeg=iQue.Last())->iLen);
       
   681         return;
       
   682         }
       
   683     TInt base=iBase;
       
   684 	TBufSegLink *next;
       
   685     if ((next=iSeg)==NULL)
       
   686         { // anSbo is not valid - set to pos=0
       
   687         next=iQue.First();
       
   688         base=0;
       
   689         }
       
   690     if (aPos<base)
       
   691         { // Look to the left
       
   692         do
       
   693             {
       
   694             next=next->Prev();
       
   695             base-=next->iLen;
       
   696             } while (aPos<base);
       
   697         }
       
   698     else
       
   699         { // Look to the right
       
   700 		TBufSegLink *nn;
       
   701         while (aPos>=(base+next->iLen) && !iQue.IsHead(nn=next->Next()))
       
   702             {
       
   703             base+=next->iLen;
       
   704             next=nn;
       
   705             }
       
   706         }
       
   707     iSeg=next;
       
   708     iBase=base;
       
   709     iOffset=aPos-base;
       
   710 	__ASSERT_DEBUG(iOffset<=iExpandSize,Panic(EBufSegSetSBO));
       
   711 	}
       
   712 
       
   713 void CBufSeg::AllocSegL(TBufSegLink *aSeg,TInt aNumber)
       
   714 //
       
   715 // Allocate a number of segments.
       
   716 //
       
   717 	{
       
   718 
       
   719 	for (TInt i=0;i<aNumber;i++)
       
   720 		{
       
   721 		TBufSegLink *pL=(TBufSegLink *)User::Alloc(sizeof(TBufSegLink)+iExpandSize);
       
   722 		if (pL==NULL)
       
   723 			{ // alloc failed - tidy up
       
   724 			while (i--)
       
   725 				FreeSegment(aSeg->Next());
       
   726 			User::Leave(KErrNoMemory);
       
   727 			}
       
   728 		new(pL) TBufSegLink;
       
   729 		pL->Enque(aSeg);
       
   730 		}
       
   731 	}
       
   732 
       
   733 EXPORT_C CBufSeg *CBufSeg::NewL(TInt anExpandSize)
       
   734 /**
       
   735 Allocates and constructs a segmented buffer.
       
   736 
       
   737 If there is insufficient memory available to allocate the segmented buffer, 
       
   738 the function leaves.
       
   739 
       
   740 @param anExpandSize The granularity of the buffer. Each segment contains (in 
       
   741                     addition to 16 bytes of overhead) this number of bytes for
       
   742                     data. Note: although a value of zero is permitted by this
       
   743                     interface, it has no meaning, and risks raising panics later
       
   744                     during execution. We suggest that you pass a positive value. 
       
   745                     
       
   746 @return If successful, a pointer to the segmented buffer object.
       
   747 
       
   748 @panic E32USER-CBase 3 if the granularity is negative.
       
   749 */
       
   750 	{
       
   751 
       
   752 	return(new(ELeave) CBufSeg(anExpandSize));
       
   753 	}
       
   754 
       
   755 EXPORT_C CBufSeg::CBufSeg(TInt anExpandSize)
       
   756 //
       
   757 // Constructor
       
   758 //
       
   759 	: CBufBase(anExpandSize)
       
   760 	{
       
   761 
       
   762 //	iSeg=NULL;
       
   763 	}
       
   764 
       
   765 EXPORT_C CBufSeg::~CBufSeg()
       
   766 /**
       
   767 Destructor.
       
   768 
       
   769 Frees all resources owned by the object, prior to its destruction.
       
   770 
       
   771 Specifically, it frees all segments allocated to the buffer.
       
   772 */
       
   773 	{
       
   774 
       
   775 	Delete(0,iSize);
       
   776 	}
       
   777 
       
   778 EXPORT_C void CBufSeg::Compress()
       
   779 /**
       
   780 Compresses the buffer so as to occupy minimal space.
       
   781 
       
   782 Fills any space in each segment of the buffer by moving contents from the next
       
   783 segment to the current one.  Where this activity results in empty segments,
       
   784 it frees the memory associated with these segments.
       
   785 
       
   786 @see CBufBase::Compress
       
   787 */
       
   788 	{
       
   789 
       
   790     if (!iSize)
       
   791         return;
       
   792     iSeg=NULL; // Invalidate current position
       
   793     TBufSegLink *p1=iQue.First();
       
   794     TBufSegLink *p2;
       
   795     while (!iQue.IsHead(p2=p1->Next()))
       
   796         {
       
   797         TInt rem=iExpandSize-p1->iLen;
       
   798         if (rem==0)
       
   799             {
       
   800             p1=p2;
       
   801             continue; // Full
       
   802             }
       
   803         if (rem>=p2->iLen)
       
   804             { // Zap the next segment
       
   805             InsertIntoSegment(p1,p1->iLen,p2+1,p2->iLen);
       
   806             FreeSegment(p2);
       
   807             continue;
       
   808             }
       
   809         InsertIntoSegment(p1,p1->iLen,p2+1,rem);  // Make full
       
   810         DeleteFromSegment(p2,0,rem);
       
   811         p1=p2;
       
   812         }
       
   813 	}
       
   814 
       
   815 EXPORT_C void CBufSeg::DoInsertL(TInt aPos,const TAny *aPtr,TInt aLength)
       
   816 //
       
   817 // Insert data at the specified position. This is quite tricky.
       
   818 // In general, the data to be copied may be broken down into the
       
   819 // following elements:
       
   820 //     s1 bytes into the current segment (p1)
       
   821 //     nseg-1 segments of self->sgbuf.hd.len (ie full segments)
       
   822 //     s2 bytes into segment nseg
       
   823 //     s3 bytes into the next segment (p2)
       
   824 // where p2 is the next segment before the insertion of nseg new segments.
       
   825 // In addition, any remaining data to the right of the insertion point must
       
   826 // be moved appropriately. In general, r1 bytes must be moved into segment
       
   827 // nseg (r2 bytes) and segment p2 (r3 bytes) where r1=r2+r3.
       
   828 //
       
   829 	{
       
   830 
       
   831     SetSBO(aPos);
       
   832     TInt slen=iExpandSize;
       
   833     TInt ofs=iOffset;	
       
   834 	TInt ll=0;
       
   835     TInt s1=0;
       
   836     TInt r1=0;
       
   837     TBufSegLink *p1=(TBufSegLink *)(&iQue); 
       
   838     TBufSegLink *p2=p1->Next(); 
       
   839 	TUint8 *pR=NULL;
       
   840     if (iSize)	
       
   841         {
       
   842         p1=iSeg;	
       
   843      	if (!iQue.IsHead(p2=p1->Prev()) && ofs==0 && p2->iLen<slen)
       
   844         	{  
       
   845         	iSeg=p1=p2;     
       
   846         	iOffset=ofs=p1->iLen;
       
   847         	iBase-=ofs;     
       
   848         	}
       
   849         s1=slen-ofs; 
       
   850         if (s1>aLength)
       
   851             s1=aLength; 
       
   852 		TInt r2=slen-p1->iLen; 
       
   853         if (aLength>r2)	
       
   854             { 
       
   855             pR=((TUint8 *)(p1+1))+ofs; 
       
   856             r1=aLength-r2; 
       
   857 			r2=p1->iLen-ofs; 
       
   858             if (r1>r2) 
       
   859                 r1=r2; 
       
   860             else
       
   861                 pR+=(r2-r1); 
       
   862             }
       
   863 		p2=p1->Next();
       
   864         ll=slen-p1->iLen;
       
   865 		if (!iQue.IsHead(p2))
       
   866 		  	ll+=slen-p2->iLen;
       
   867         }
       
   868     TUint8 *pB=((TUint8 *)aPtr)+s1; 
       
   869     TInt lrem=aLength-s1;
       
   870     TBufSegLink *pP=p1;
       
   871     if (aLength>ll)
       
   872         {// Need some more segments
       
   873 		TInt nseg=(slen-1+aLength-ll)/slen;
       
   874         AllocSegL(p1,nseg); // Could leave
       
   875         while (nseg--)
       
   876             { // Copy into allocated segments
       
   877             pP=pP->Next();
       
   878             TInt gap=slen;
       
   879             if (lrem<gap)
       
   880                 gap=lrem;
       
   881 			InsertIntoSegment(pP,0,aPtr==NULL ? NULL : pB,gap);
       
   882             pB+=gap;
       
   883             lrem-=gap;
       
   884             }
       
   885         }
       
   886     if (lrem) 
       
   887         {	
       
   888 		InsertIntoSegment(p2,0,aPtr==NULL ? NULL : pB,lrem); 
       
   889         InsertIntoSegment(p2,lrem,pR,r1); 
       
   890         }
       
   891     else 
       
   892         { 
       
   893         TInt r2=0;
       
   894         if (pP!=p1)
       
   895             {
       
   896             r2=slen-pP->iLen; 
       
   897             if (r2>r1)
       
   898                 r2=r1;	
       
   899             }
       
   900         InsertIntoSegment(pP,pP->iLen,pR,r2); // Moved from p1 
       
   901         InsertIntoSegment(p2,0,pR+r2,r1-r2); // Also moved from p1
       
   902         }
       
   903     p1->iLen-=r1;
       
   904 	InsertIntoSegment(p1,ofs,aPtr,s1);
       
   905     iSize+=aLength;
       
   906 	}
       
   907 
       
   908 EXPORT_C void CBufSeg::Delete(TInt aPos,TInt aLength)
       
   909 /**
       
   910 Deletes data from the buffer.
       
   911 
       
   912 During deletion, shuffling is minimised by deleting intermediate segments
       
   913 and allowing segments to contain less data than the buffer granularity.
       
   914 
       
   915 @param aPos    Buffer position where the deletion will begin; must be in the 
       
   916                range zero to (Size() minus the length of the data
       
   917                to be deleted). 
       
   918 @param aLength The number of bytes to be deleted.
       
   919 
       
   920 @see CBufBase::Delete
       
   921 */
       
   922 	{
       
   923 
       
   924     if (aLength==0)
       
   925         return;
       
   926     SetSBO(aPos);
       
   927     TInt ofs=iOffset;
       
   928     __ASSERT_ALWAYS((iBase+ofs+aLength)<=iSize,Panic(EBufSegDeleteBeyondEnd));
       
   929     iSize-=aLength;
       
   930     TBufSegLink *p1=iSeg;
       
   931 	TBufSegLink *p2;
       
   932     TInt rem=p1->iLen-ofs;
       
   933     FOREVER
       
   934         {
       
   935         p2=p1->Next();
       
   936         TInt gap=aLength;
       
   937         if (gap>rem)
       
   938             gap=rem;
       
   939         DeleteFromSegment(p1,ofs,gap);
       
   940         if (p1->iLen==0)
       
   941             {
       
   942             iSeg=NULL;
       
   943             FreeSegment(p1);
       
   944             }
       
   945         p1=p2;
       
   946         if ((aLength-=gap)==0)
       
   947             break;
       
   948         rem=p1->iLen;
       
   949         ofs=0;
       
   950         }
       
   951     if (iSize)
       
   952         {
       
   953         p1=p2->Prev();
       
   954         if (!iQue.IsHead(p1) && !iQue.IsHead(p2))
       
   955             {
       
   956             if ((p1->iLen+p2->iLen)<=iExpandSize)
       
   957                 { // Join to the right
       
   958                 InsertIntoSegment(p1,p1->iLen,p2+1,p2->iLen);
       
   959                 FreeSegment(p2);
       
   960                 }
       
   961             }
       
   962         }
       
   963     SetSBO(aPos);
       
   964 	}
       
   965 
       
   966 EXPORT_C TPtr8 CBufSeg::Ptr(TInt aPos)
       
   967 /**
       
   968 Gets a pointer descriptor to represent the data starting at the specified
       
   969 data byte through to the end of the contiguous region containing that byte.
       
   970 
       
   971 The time needed for calculation of the pointer depends on how many segments
       
   972 there are in the buffer, and how near the target segment is to the segment
       
   973 which was last used in the buffer.
       
   974 
       
   975 @param aPos Buffer position: must be in range zero to Size().
       
   976 	 
       
   977 @return Descriptor representing the data starting at aPos to the end of
       
   978         the contiguous region containing that byte.     	
       
   979 */
       
   980 	{
       
   981 
       
   982     if (iSize==0)
       
   983 		return(TPtr8(NULL,0,0));
       
   984     SetSBO(aPos);
       
   985 	TInt len=iSeg->iLen-iOffset;
       
   986     return(TPtr8(((TUint8 *)(iSeg+1))+iOffset,len,len));
       
   987 	}
       
   988 
       
   989 EXPORT_C TPtr8 CBufSeg::BackPtr(TInt aPos)
       
   990 //
       
   991 // Return a pointer to the buffer which has the maximum amount of data
       
   992 // before aPos, and the amount of data remaining.  
       
   993 //
       
   994 /**
       
   995 Gets a pointer descriptor to represent the data starting at the beginning
       
   996 of the contiguous region containing that byte through to the byte immediately
       
   997 preceding the specified byte.
       
   998 
       
   999 The descriptor always points to the beginning of the segment containing the
       
  1000 specified byte. The time needed for calculation of the pointer depends on how
       
  1001 many segments there are in the buffer, and how near the target segment is to
       
  1002 the segment which was last used in the buffer.
       
  1003 
       
  1004 @param aPos Buffer position: must be in range zero to Size().
       
  1005 
       
  1006 @return Descriptor representing the back contiguous region. 
       
  1007 
       
  1008 @see CBufBase::BackPtr
       
  1009 */
       
  1010 
       
  1011 
       
  1012 	{
       
  1013 
       
  1014     if (aPos==0)
       
  1015 		return(TPtr8(NULL,0,0));
       
  1016     SetSBO(aPos);
       
  1017     if (iOffset)
       
  1018         return(TPtr8((TUint8 *)(iSeg+1),iOffset,iOffset));
       
  1019     TBufSegLink *pL=iSeg->Prev();
       
  1020 	TInt len=pL->iLen;
       
  1021 	return(TPtr8((TUint8 *)(pL+1),len,len));
       
  1022 	}
       
  1023