diff -r c55016431358 -r 0a7b44b10206 symport/e32/euser/cbase/ub_buf.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/symport/e32/euser/cbase/ub_buf.cpp Thu Jun 25 15:59:54 2009 +0100 @@ -0,0 +1,1023 @@ +// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Symbian Foundation License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32\euser\cbase\ub_buf.cpp +// +// + +#include "ub_std.h" + +class TBufSegLink : public TDblQueLink + { +public: + inline TBufSegLink() : iLen(0) {} + inline TBufSegLink *Next() const {return((TBufSegLink *)iNext);} + inline TBufSegLink *Prev() const {return((TBufSegLink *)iPrev);} +public: + TInt iLen; + }; + +EXPORT_C CBufBase::CBufBase(TInt anExpandSize) +// +// Constructor +// +/** +@internalComponent +*/ + { + + __ASSERT_ALWAYS(anExpandSize>=0,Panic(EBufExpandSizeNegative)); +// iSize=0; + iExpandSize=anExpandSize; + } + +EXPORT_C CBufBase::~CBufBase() +/** +Destructor +*/ + { + } + +EXPORT_C void CBufBase::Reset() +/** +Deletes all data in the buffer. + +Its behaviour is the same as calling Delete(0,Size()). +The buffer is compressed before the function returns. +*/ + { + + if (iSize) + Delete(0,iSize); + Compress(); + } + +EXPORT_C void CBufBase::Read(TInt aPos,TDes8 &aDes) const +// +// Read up to aDes.MaxLength() bytes. +// +/** +Reads data from the buffer into a descriptor. + +Data, starting at the specified buffer position is written to the descriptor, +filling the descriptor. + +@param aPos Buffer position from which data is read: must be in range zero + to Size(). +@param aDes On return, contains the data read from the buffer; its MaxLength() + specifies the amount of data to be read. +*/ + { + + Read(aPos,aDes,aDes.MaxLength()); + } + +EXPORT_C void CBufBase::Read(TInt aPos,TDes8 &aDes,TInt aLength) const +/** +Reads the specified number of bytes of data from the buffer into a descriptor. + +@param aPos Buffer position from which data is read: must be in range zero + to (Size() minus the length of the data to be read). +@param aDes On return, contains data read from the buffer. +@param aLength The length of the data to be read. +*/ + { + + aDes.SetLength(aLength); + Read(aPos,(TAny *)aDes.Ptr(),aLength); + } + +EXPORT_C void CBufBase::Read(TInt aPos,TAny *aPtr,TInt aLength) const +/** +Reads the specified number of bytes of data from the buffer into a specified +address. + +@param aPos Buffer position from which data is read: must be in range zero + to (Size() minus the length of the data to be read). +@param aPtr The address into which the data should be read. +@param aLength The length of the data to be read. +*/ + { + + if (aLength==0) + return; + __ASSERT_ALWAYS(aLength>0,Panic(EBufReadLengthNegative)); + __ASSERT_ALWAYS((aPos+aLength)<=iSize,Panic(EBufReadBeyondEnd)); + TUint8 *pT=(TUint8 *)aPtr; + while (aLength) + { + TPtr8 p=((CBufBase *)this)->Ptr(aPos); + TInt s=Min(p.Length(),aLength); + pT=Mem::Copy(pT,p.Ptr(),s); + aLength-=s; + aPos+=s; + } + } + +EXPORT_C void CBufBase::Write(TInt aPos,const TDesC8 &aDes) +// +// Write aDes.Length() characters to the buffer. Does not cause any expansion. +// +/** +Writes data from a descriptor to the buffer. + +The data in the descriptor overwrites the data in the buffer from the insertion +point onwards. + +No new space is allocated; this function cannot fail (provided the parameters +are specified within the bounds of the buffer and descriptor). + +No shuffling occurs; new data is written to the memory locations occupied +by the data it overwrites. + +@param aPos Buffer position at which data will begin to be written; must be + in range zero to (Size() minus the length of the data + to be written). +@param aDes Contains the data to be written. The length of data to be written + is the descriptor length. +*/ + { + + Write(aPos,aDes.Ptr(),aDes.Length()); + } + +EXPORT_C void CBufBase::Write(TInt aPos,const TDesC8 &aDes,TInt aLength) +// +// Write aDes.Length() characters to the buffer. Does not cause any expansion. +// +/** +Writes the specified number of bytes of data from a descriptor to the buffer. + +The data in the descriptor overwrites the data in the buffer from the insertion +point onwards. + +No new space is allocated; this function cannot fail (provided the parameters +are specified within the bounds of the buffer and descriptor). + +No shuffling occurs; new data is written to the memory locations occupied +by the data it overwrites. + +@param aPos Buffer position at which data will begin to be written; must be + in range zero to (Size() minus the length of the data to + be written). +@param aDes Contains the data to be written. +@param aLength The length of the data to be written. +*/ + { + + Write(aPos,aDes.Ptr(),aLength); + } + +EXPORT_C void CBufBase::Write(TInt aPos,const TAny *aPtr,TInt aLength) +/** +Writes the specified number of bytes of data from the specified address to the +buffer. + +The data in the buffer is overwritten from the insertion point onwards. + +No new space is allocated; this function cannot fail (provided the parameters +are specified within the bounds of the buffer and descriptor). + +No shuffling occurs: new data is written to the memory locations occupied +by the data it overwrites. + +@param aPos Buffer position at which data will begin to be written; must be + in range zero to (Size() minus the length of the data to + be written). +@param aPtr The address of the data to be written. +@param aLength The length of the data to be written. + +@panic E32USER-CBase 7, if aLength is not positive +@panic E32USER-CBase 5, if aPos + aLength is greater than the number of + data bytes in the buffer, i.e. if the target appears + to be outside the buffer. +*/ + { + + if (aLength==0) + return; + __ASSERT_ALWAYS(aLength>0,Panic(EBufWriteLengthNegative)); + __ASSERT_ALWAYS((aPos+aLength)<=iSize,Panic(EBufWriteBeyondEnd)); + const TUint8 *pS=(const TUint8 *)aPtr; + while (aLength) + { + TPtr8 p=Ptr(aPos); + TInt s=Min(p.Length(),aLength); + Mem::Copy((TAny *)p.Ptr(),pS,s); + pS+=s; + aLength-=s; + aPos+=s; + } + } + +EXPORT_C void CBufBase::InsertL(TInt aPos,const TDesC8 &aDes) +// +// Insert aDes.Length() bytes into the buffer. +// +/** +Inserts data into the buffer. + +Data at and beyond the insertion position is moved to make way for the inserted +data. Data before the insertion position remains in place. + +Notes: + +1. Insertion may require more buffer space to be allocated. + +2. In the case of flat buffers, the buffer is extended by a ReAllocL() of the + buffer's heap cell, to the smallest multiple of the granularity that will + contain the data required. If this reallocation fails, the insertion is + impossible and a leave occurs. + +3. In the case of segmented buffers, a reallocation is performed if the segment + containing the insertion position has insufficient space, and + immediately-neighbouring segments cannot be used to contain the new data. + As many new segments as are necessary to contain the inserted data are + allocated. Each new segment's length is the buffer's granularity. + If extension or new allocation fails, a leave occurs. + +4. Insertion may also require data to be shuffled. In the case of flat buffers, + data beyond the insertion point is shuffled up to create a gap; the new data + is then inserted into this gap. In the case of segmented buffers, shuffling + is minimised by inserting the new data into newly-allocated buffers, and + shuffling only immediately-neighbouring buffers if possible. This may result + in some wastage of space, but is much more time-efficient for large amounts + of data. + +@param aPos Buffer position before which the data will be inserted; must be + in range zero to Size(). +@param aDes The data to be inserted; the length of the data is the descriptor + length. + +@leave KErrNoMemory If the insertion requires a bigger buffer, and the + necessary allocation or re-allocation fails. +*/ + { + + InsertL(aPos,aDes.Ptr(),aDes.Length()); + } + +EXPORT_C void CBufBase::InsertL(TInt aPos,const TDesC8 &aDes,TInt aLength) +// +// Insert aLength bytes into the buffer. +// +/** +Inserts the specified number of bytes of data from a descriptor into +the buffer. + +aLength bytes of data from aDes are inserted into the buffer at aPos. Data at +and beyond the insertion position is moved to make way for the inserted data. +Data before the insertion position remains in place. + +Notes: + +1. Insertion may require more buffer space to be allocated. + +2. In the case of flat buffers, the buffer is extended by a ReAllocL() of the + buffer's heap cell, to the smallest multiple of the granularity that will + contain the data required. If this reallocation fails, the insertion is + impossible and a leave occurs. + +3. In the case of segmented buffers, a reallocation is performed if the segment + containing the insertion position has insufficient space, and + immediately-neighbouring segments cannot be used to contain the new data. + As many new segments as are necessary to contain the inserted data are + allocated. Each new segment's length is the buffer's granularity. + If extension or new allocation fails, a leave occurs. + +4. Insertion may also require data to be shuffled. In the case of flat buffers, + data beyond the insertion point is shuffled up to create a gap: the new data + is then inserted into this gap. In the case of segmented buffers, shuffling + is minimised by inserting the new data into newly-allocated buffers, + and shuffling only immediately-neighbouring buffers if possible. + This may result in some wastage of space, but is much more time-efficient + for large amounts of data. + +@param aPos Buffer position before which the data will be inserted; must be + in range zero to Size(). +@param aDes The data to be inserted. +@param aLength The length of data to be inserted. + +@leave KErrNoMemory If the insertion requires a bigger buffer, and the + necessary allocation or re-allocation fails. +*/ + { + + InsertL(aPos,aDes.Ptr(),aLength); + } + +EXPORT_C void CBufBase::InsertL(TInt aPos,const TAny *aPtr,TInt aLength) +/** +Inserts bytes of data from the specified address into the buffer. + +Inserts aLength bytes of data found at address aPtr into the buffer at aPos. +Data at and beyond the insertion position is moved to make way for the inserted +data. Data before the insertion position remains in place. + +Notes: + +1. Insertion may require more buffer space to be allocated. + +2. In the case of flat buffers, the buffer is extended by a ReAllocL() of the + buffer's heap cell, to the smallest multiple of the granularity that will + contain the data required. If this reallocation fails, the insertion is + impossible and a leave occurs. + +2. In the case of segmented buffers, a reallocation is performed if the segment + containing the insertion position has insufficient space, and + immediately-neighbouring segments cannot be used to contain the new data. + As many new segments as are necessary to contain the inserted data are + allocated. Each new segment's length is the buffer's granularity. + If extension or new allocation fails, a leave occurs. + +4. Insertion may also require data to be shuffled. In the case of flat buffers, + data beyond the insertion point is shuffled up to create a gap: the new data + is then inserted into this gap. In the case of segmented buffers, shuffling + is minimised by inserting the new data into newly-allocated buffers, and + shuffling only immediately-neighbouring buffers if possible. This may result + in some wastage of space, but is much more time-efficient for large amounts + of data. + +@param aPos Buffer position before which the data will be inserted: must be + in range zero to Size(). +@param aPtr The address of the data to be inserted. +@param aLength The length of the data to be inserted. + +@leave KErrNoMemory If the insertion requires a bigger buffer, and the + necessary allocation or re-allocation fails. +*/ + { + + if (aLength==0) + return; + __ASSERT_ALWAYS(aLength>0,Panic(EBufInsertLengthNegative)); + __ASSERT_ALWAYS(aPtr,Panic(EBufInsertBadPtr)); + DoInsertL(aPos,aPtr,aLength); + } + +EXPORT_C void CBufBase::ExpandL(TInt aPos,TInt aLength) +/** +Inserts an uninitialised region into the buffer. + +Data at and beyond the insertion position is moved to make way for the inserted +region. Data before the insertion position remains in place. + +Note: + +1. The inserted region is not initialised. After using ExpandL(), you should + then use a series of Write()s to fill this region with data. + +2. Use ExpandL() followed by a series of Write()s when you know the amount of + data to be inserted, in advance. It is more efficient than a series of + InsertL()s. In addition, once the result of the ExpandL() has been checked, + it is guaranteed that the Write()s do not leave, which can sometimes be + useful. + +@param aPos Buffer position before which the region will be inserted; must + be in range zero to Size(). +@param aLength The length of the region to be inserted. +*/ + { + + if (aLength==0) + return; + __ASSERT_ALWAYS(aLength>0,Panic(EBufInsertLengthNegative)); + DoInsertL(aPos,NULL,aLength); + } + +EXPORT_C void CBufBase::ResizeL(TInt aSize) +/** +Re-sizes the buffer to the specified size. + +The new size can be larger or smaller than the existing size. + +If the new size is larger than the existing size, the buffer is expanded by +adding uninitialised data to the end of it. + +If the new size is smaller than the existing size, the buffer is reduced; +any data at the end of the buffer is lost. + +Notes: + +1. If the new size is larger than the existing size, the function is equivalent + to Delete(aSize,Size()-aSize). + +2. If the new size is smaller than the existing size, the function is equivalent + to ExpandL((Size(),aSize-Size()). + +3. The motivations for using ResizeL() are the same as those for using Delete() + and ExpandL(). + +@param aSize The new size of the buffer; this value must be greater than or + equal to zero. +*/ + { + + TInt excess=iSize-aSize; + if (excess>0) + Delete(aSize,excess); + else + ExpandL(iSize,-excess); + } + +EXPORT_C CBufFlat *CBufFlat::NewL(TInt anExpandSize) +/** +Allocates and constructs a flat buffer. + +If there is insufficient memory available to allocate the flat buffer, the +function leaves. + +@param anExpandSize The granularity of buffer expansion. Additional space, + when required, is always allocated in multiples of + this number. Note: although a value of zero is permitted + by this interface, it has no meaning, and risks raising + panics later during execution. We suggest that you pass + a positive value. + +@return A pointer to the flat buffer object. + +@panic E32USER-CBase 3 if the granularity is negative. +*/ + { + + return(new(ELeave) CBufFlat(anExpandSize)); + } + +EXPORT_C CBufFlat::CBufFlat(TInt anExpandSize) +// +// Constructor +// +/** +@internalComponent +*/ + : CBufBase(anExpandSize) + { + +// iMaxSize=0; +// iPtr=NULL; + } + +EXPORT_C CBufFlat::~CBufFlat() +/** +Destructor. + +Frees all resources owned by the object, prior to its destruction. +Specifically, it frees the allocated cell used as a buffer. +*/ + { + + User::Free(iPtr); + } + +EXPORT_C void CBufFlat::Compress() +/** +Compresses the buffer so as to occupy minimal space. + +This frees any unused memory at the end of the buffer. + +@see CBufBase::Compress +*/ + { + + SetReserveL(iSize); + } + +EXPORT_C void CBufFlat::SetReserveL(TInt aSize) +/** +Specifies a minimum amount of space which the flat buffer should occupy. + +If the required size is zero, the heap cell is deleted. If it is different +from the current size, the heap cell is rellocated accordingly. + +@param aSize The size of the buffer required. If there is no data in the + buffer, i.e. Size() returns zero, then this value + can be zero, which causes the buffer's allocated heap cell + to be deleted. + +@panic E32USER-CBase 10, if aSize is negative. +@panic E32USER-CBase 11, if there is data in the buffer, and aSize is less than + the value returned by Size(). +*/ + { + + __ASSERT_ALWAYS(aSize>=0,Panic(EBufFlatReserveNegative)); + __ASSERT_ALWAYS(aSize>=iSize,Panic(EBufFlatReserveSetTooSmall)); + if (!aSize) + { + User::Free(iPtr); + iPtr=NULL; + } + else + iPtr=(TUint8 *)User::ReAllocL(iPtr,aSize); + iMaxSize=aSize; + } + +EXPORT_C void CBufFlat::DoInsertL(TInt aPos,const TAny *aPtr,TInt aLength) +// +// Insert into the buffer. Can cause expansion. +// + { + + __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange)); + TInt len=iSize+aLength; + if (len>iMaxSize) + { + TInt r=len-iMaxSize; + r=((r/iExpandSize)+1)*iExpandSize; + SetReserveL(iMaxSize+r); + } + Mem::Copy(iPtr+aPos+aLength,iPtr+aPos,iSize-aPos); + if (aPtr) + Mem::Copy(iPtr+aPos,aPtr,aLength); + iSize+=aLength; + } + +EXPORT_C void CBufFlat::Delete(TInt aPos,TInt aLength) +/** +Deletes data from the buffer. + +During deletion, any data beyond the deleted data is shuffled up so that +the buffer contents are contiguous. No memory is freed. + +@param aPos Buffer position where the deletion will begin; must be in the + range zero to (Size() minus the length of the data + to be deleted). +@param aLength The number of bytes to be deleted. + +@panic E32USER-CBase 12, if aPos is negative or is greater than the + current size of the buffer. +@panic E32USER-CBase 13, if aPos + aLength is greater than the + current size of the buffer. + +@see CBufBase::Delete +*/ + { + + __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange)); + __ASSERT_ALWAYS((aPos+aLength)<=iSize,Panic(EBufFlatDeleteBeyondEnd)); + Mem::Copy(iPtr+aPos,iPtr+aPos+aLength,iSize-aLength-aPos); + iSize-=aLength; + } + +EXPORT_C TPtr8 CBufFlat::Ptr(TInt aPos) +/** +Gets a pointer descriptor to represent the data starting at the specified +data byte through to the end of the contiguous region containing that byte. + +Calculation of the pointer and length involves only a few machine instructions +and is independent of the data contained in the buffer. + +@param aPos Buffer position: must be in range zero to Size(). + +@return Descriptor representing the data starting at aPos to the end of + the buffer. +*/ + { + + __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange)); + TInt len=iSize-aPos; + return(TPtr8(iPtr+aPos,len,len)); + } + +EXPORT_C TPtr8 CBufFlat::BackPtr(TInt aPos) +// +// Return a pointer to the buffer which has the maximum amount of data +// before aPos, and the amount of data remaining. +// +/** +Gets a pointer descriptor to represent the data starting at the beginning +of the contiguous region containing that byte through to the byte immediately +preceding the specified byte. + +The descriptor always points to the beginning of the buffer containing +the specified byte. Calculation of the pointer and length involves only a few +machine instructions and is independent of the data contained in the buffer. + +@param aPos Buffer position: must be in range zero to Size(). + +@return Descriptor representing the back contiguous region. + +@see CBufBase::BackPtr +*/ + { + + __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufFlatPosOutOfRange)); + return(TPtr8(iPtr,aPos,aPos)); + } + +void CBufSeg::InsertIntoSegment(TBufSegLink *aSeg,TInt anOffset,const TAny *aPtr,TInt aLength) +// +// Insert into the segment. +// + { + + if (aLength) + { + TUint8 *pS=((TUint8 *)(aSeg+1))+anOffset; + Mem::Copy(pS+aLength,pS,aSeg->iLen-anOffset); + if (aPtr) + Mem::Copy(pS,aPtr,aLength); + aSeg->iLen+=aLength; + } + } + +void CBufSeg::DeleteFromSegment(TBufSegLink *aSeg,TInt anOffset,TInt aLength) +// +// Delete from the segment. +// + { + + if (aLength) + { + TUint8 *pS=((TUint8 *)(aSeg+1))+anOffset; + Mem::Copy(pS,pS+aLength,aSeg->iLen-anOffset-aLength); + aSeg->iLen-=aLength; + } + } + +void CBufSeg::FreeSegment(TBufSegLink *aSeg) +// +// Free an entire segment. +// + { + + aSeg->Deque(); + User::Free(aSeg); + } + +void CBufSeg::SetSBO(TInt aPos) +// +// Set a segment-base-offset struct (SBO) to a new pos. +// If the initial psbo->seg is not NULL, it assumes that it is a valid +// SBO for a different position and counts relative to the initial SBO +// to set the desired position. If the initial psbo->seg is NULL, it starts +// scanning from the beginning ie pos=0. +// When the position is between segments A and B, there are two equivalent +// positions: (1) at the beginning of B and (2) at the end of A. +// Option (1) is suitable for referencing the data and deleting. +// Option (2) is best for insertion when A is not full. +// This function uses option (1) and will always set the SBO to the +// beginning of the next segment. It does however set to the end of the +// last segment when pos is equal to the number of bytes in the buffer. +// + { + + __ASSERT_ALWAYS(aPos>=0 && aPos<=iSize,Panic(EBufSegPosOutOfRange)); + if (aPos==iSize) + { // Positioning to end is treated as a special case + iSeg=0; + if (iSize) + iBase=aPos-(iOffset=(iSeg=iQue.Last())->iLen); + return; + } + TInt base=iBase; + TBufSegLink *next; + if ((next=iSeg)==NULL) + { // anSbo is not valid - set to pos=0 + next=iQue.First(); + base=0; + } + if (aPosPrev(); + base-=next->iLen; + } while (aPos=(base+next->iLen) && !iQue.IsHead(nn=next->Next())) + { + base+=next->iLen; + next=nn; + } + } + iSeg=next; + iBase=base; + iOffset=aPos-base; + __ASSERT_DEBUG(iOffset<=iExpandSize,Panic(EBufSegSetSBO)); + } + +void CBufSeg::AllocSegL(TBufSegLink *aSeg,TInt aNumber) +// +// Allocate a number of segments. +// + { + + for (TInt i=0;iNext()); + User::Leave(KErrNoMemory); + } + new(pL) TBufSegLink; + pL->Enque(aSeg); + } + } + +EXPORT_C CBufSeg *CBufSeg::NewL(TInt anExpandSize) +/** +Allocates and constructs a segmented buffer. + +If there is insufficient memory available to allocate the segmented buffer, +the function leaves. + +@param anExpandSize The granularity of the buffer. Each segment contains (in + addition to 16 bytes of overhead) this number of bytes for + data. Note: although a value of zero is permitted by this + interface, it has no meaning, and risks raising panics later + during execution. We suggest that you pass a positive value. + +@return If successful, a pointer to the segmented buffer object. + +@panic E32USER-CBase 3 if the granularity is negative. +*/ + { + + return(new(ELeave) CBufSeg(anExpandSize)); + } + +EXPORT_C CBufSeg::CBufSeg(TInt anExpandSize) +// +// Constructor +// + : CBufBase(anExpandSize) + { + +// iSeg=NULL; + } + +EXPORT_C CBufSeg::~CBufSeg() +/** +Destructor. + +Frees all resources owned by the object, prior to its destruction. + +Specifically, it frees all segments allocated to the buffer. +*/ + { + + Delete(0,iSize); + } + +EXPORT_C void CBufSeg::Compress() +/** +Compresses the buffer so as to occupy minimal space. + +Fills any space in each segment of the buffer by moving contents from the next +segment to the current one. Where this activity results in empty segments, +it frees the memory associated with these segments. + +@see CBufBase::Compress +*/ + { + + if (!iSize) + return; + iSeg=NULL; // Invalidate current position + TBufSegLink *p1=iQue.First(); + TBufSegLink *p2; + while (!iQue.IsHead(p2=p1->Next())) + { + TInt rem=iExpandSize-p1->iLen; + if (rem==0) + { + p1=p2; + continue; // Full + } + if (rem>=p2->iLen) + { // Zap the next segment + InsertIntoSegment(p1,p1->iLen,p2+1,p2->iLen); + FreeSegment(p2); + continue; + } + InsertIntoSegment(p1,p1->iLen,p2+1,rem); // Make full + DeleteFromSegment(p2,0,rem); + p1=p2; + } + } + +EXPORT_C void CBufSeg::DoInsertL(TInt aPos,const TAny *aPtr,TInt aLength) +// +// Insert data at the specified position. This is quite tricky. +// In general, the data to be copied may be broken down into the +// following elements: +// s1 bytes into the current segment (p1) +// nseg-1 segments of self->sgbuf.hd.len (ie full segments) +// s2 bytes into segment nseg +// s3 bytes into the next segment (p2) +// where p2 is the next segment before the insertion of nseg new segments. +// In addition, any remaining data to the right of the insertion point must +// be moved appropriately. In general, r1 bytes must be moved into segment +// nseg (r2 bytes) and segment p2 (r3 bytes) where r1=r2+r3. +// + { + + SetSBO(aPos); + TInt slen=iExpandSize; + TInt ofs=iOffset; + TInt ll=0; + TInt s1=0; + TInt r1=0; + TBufSegLink *p1=(TBufSegLink *)(&iQue); + TBufSegLink *p2=p1->Next(); + TUint8 *pR=NULL; + if (iSize) + { + p1=iSeg; + if (!iQue.IsHead(p2=p1->Prev()) && ofs==0 && p2->iLeniLen; + iBase-=ofs; + } + s1=slen-ofs; + if (s1>aLength) + s1=aLength; + TInt r2=slen-p1->iLen; + if (aLength>r2) + { + pR=((TUint8 *)(p1+1))+ofs; + r1=aLength-r2; + r2=p1->iLen-ofs; + if (r1>r2) + r1=r2; + else + pR+=(r2-r1); + } + p2=p1->Next(); + ll=slen-p1->iLen; + if (!iQue.IsHead(p2)) + ll+=slen-p2->iLen; + } + TUint8 *pB=((TUint8 *)aPtr)+s1; + TInt lrem=aLength-s1; + TBufSegLink *pP=p1; + if (aLength>ll) + {// Need some more segments + TInt nseg=(slen-1+aLength-ll)/slen; + AllocSegL(p1,nseg); // Could leave + while (nseg--) + { // Copy into allocated segments + pP=pP->Next(); + TInt gap=slen; + if (lremiLen; + if (r2>r1) + r2=r1; + } + InsertIntoSegment(pP,pP->iLen,pR,r2); // Moved from p1 + InsertIntoSegment(p2,0,pR+r2,r1-r2); // Also moved from p1 + } + p1->iLen-=r1; + InsertIntoSegment(p1,ofs,aPtr,s1); + iSize+=aLength; + } + +EXPORT_C void CBufSeg::Delete(TInt aPos,TInt aLength) +/** +Deletes data from the buffer. + +During deletion, shuffling is minimised by deleting intermediate segments +and allowing segments to contain less data than the buffer granularity. + +@param aPos Buffer position where the deletion will begin; must be in the + range zero to (Size() minus the length of the data + to be deleted). +@param aLength The number of bytes to be deleted. + +@see CBufBase::Delete +*/ + { + + if (aLength==0) + return; + SetSBO(aPos); + TInt ofs=iOffset; + __ASSERT_ALWAYS((iBase+ofs+aLength)<=iSize,Panic(EBufSegDeleteBeyondEnd)); + iSize-=aLength; + TBufSegLink *p1=iSeg; + TBufSegLink *p2; + TInt rem=p1->iLen-ofs; + FOREVER + { + p2=p1->Next(); + TInt gap=aLength; + if (gap>rem) + gap=rem; + DeleteFromSegment(p1,ofs,gap); + if (p1->iLen==0) + { + iSeg=NULL; + FreeSegment(p1); + } + p1=p2; + if ((aLength-=gap)==0) + break; + rem=p1->iLen; + ofs=0; + } + if (iSize) + { + p1=p2->Prev(); + if (!iQue.IsHead(p1) && !iQue.IsHead(p2)) + { + if ((p1->iLen+p2->iLen)<=iExpandSize) + { // Join to the right + InsertIntoSegment(p1,p1->iLen,p2+1,p2->iLen); + FreeSegment(p2); + } + } + } + SetSBO(aPos); + } + +EXPORT_C TPtr8 CBufSeg::Ptr(TInt aPos) +/** +Gets a pointer descriptor to represent the data starting at the specified +data byte through to the end of the contiguous region containing that byte. + +The time needed for calculation of the pointer depends on how many segments +there are in the buffer, and how near the target segment is to the segment +which was last used in the buffer. + +@param aPos Buffer position: must be in range zero to Size(). + +@return Descriptor representing the data starting at aPos to the end of + the contiguous region containing that byte. +*/ + { + + if (iSize==0) + return(TPtr8(NULL,0,0)); + SetSBO(aPos); + TInt len=iSeg->iLen-iOffset; + return(TPtr8(((TUint8 *)(iSeg+1))+iOffset,len,len)); + } + +EXPORT_C TPtr8 CBufSeg::BackPtr(TInt aPos) +// +// Return a pointer to the buffer which has the maximum amount of data +// before aPos, and the amount of data remaining. +// +/** +Gets a pointer descriptor to represent the data starting at the beginning +of the contiguous region containing that byte through to the byte immediately +preceding the specified byte. + +The descriptor always points to the beginning of the segment containing the +specified byte. The time needed for calculation of the pointer depends on how +many segments there are in the buffer, and how near the target segment is to +the segment which was last used in the buffer. + +@param aPos Buffer position: must be in range zero to Size(). + +@return Descriptor representing the back contiguous region. + +@see CBufBase::BackPtr +*/ + + + { + + if (aPos==0) + return(TPtr8(NULL,0,0)); + SetSBO(aPos); + if (iOffset) + return(TPtr8((TUint8 *)(iSeg+1),iOffset,iOffset)); + TBufSegLink *pL=iSeg->Prev(); + TInt len=pL->iLen; + return(TPtr8((TUint8 *)(pL+1),len,len)); + } +