symport/e32/euser/cbase/ub_buf.cpp
changeset 1 0a7b44b10206
child 2 806186ab5e14
--- /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 (aPos<base)
+        { // Look to the left
+        do
+            {
+            next=next->Prev();
+            base-=next->iLen;
+            } while (aPos<base);
+        }
+    else
+        { // Look to the right
+		TBufSegLink *nn;
+        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;i<aNumber;i++)
+		{
+		TBufSegLink *pL=(TBufSegLink *)User::Alloc(sizeof(TBufSegLink)+iExpandSize);
+		if (pL==NULL)
+			{ // alloc failed - tidy up
+			while (i--)
+				FreeSegment(aSeg->Next());
+			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->iLen<slen)
+        	{  
+        	iSeg=p1=p2;     
+        	iOffset=ofs=p1->iLen;
+        	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 (lrem<gap)
+                gap=lrem;
+			InsertIntoSegment(pP,0,aPtr==NULL ? NULL : pB,gap);
+            pB+=gap;
+            lrem-=gap;
+            }
+        }
+    if (lrem) 
+        {	
+		InsertIntoSegment(p2,0,aPtr==NULL ? NULL : pB,lrem); 
+        InsertIntoSegment(p2,lrem,pR,r1); 
+        }
+    else 
+        { 
+        TInt r2=0;
+        if (pP!=p1)
+            {
+            r2=slen-pP->iLen; 
+            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));
+	}
+