textrendering/texthandling/sfields/FLDSET.CPP
changeset 0 1fb32624e06b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/texthandling/sfields/FLDSET.CPP	Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,684 @@
+/*
+* Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+#include <e32std.h>
+#include <e32base.h>
+
+#include "FLDSET.H"
+#include "FLDDEF.H"
+#include "FLDARRAY.H"
+#include "FLDSTD.H"
+
+
+EXPORT_C void CTextFieldSet::__DbgTestInvariant()const
+// Provides class invariants.  Explanations below:
+//
+	{
+#ifdef _DEBUG
+	if (!iFieldArray)
+		return;
+// check that every entry in the array has length >=0 and that all but the last have valid header handles
+	TBool valid = ETrue;
+	TInt index = iFieldArray->Count()-1;
+	if (index<0)
+		valid = EFalse;
+	else 
+		{// check last entry: should have null fieldHeader, zero field length and non-negative PreFieldLen
+		if ( (*iFieldArray)[index].iFieldHeader.iField
+		||(*iFieldArray)[index].iFieldValueLen!=0
+		||(*iFieldArray)[index].iPreFieldLen<0 )
+			{
+			valid = EFalse;
+			}
+		index--;
+		// check the other entries: should have non-null fieldHeader and non-negative field length and PreFieldLen
+		for (; (index>=0)&&(valid) ; index--)
+			{
+			if ((*iFieldArray)[index].iFieldValueLen<0
+				||(*iFieldArray)[index].iPreFieldLen<0 )
+					{
+					valid = EFalse;
+					}
+			}
+		}
+	__ASSERT_ALWAYS(valid,User::Invariant());
+#endif
+	}
+
+
+EXPORT_C CTextFieldSet* CTextFieldSet::NewL(TInt aDocumentLength)
+	{
+	CTextFieldSet* self=new(ELeave) CTextFieldSet();
+	CleanupStack::PushL(self);
+	self->ConstructL(aDocumentLength);
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+EXPORT_C CTextFieldSet* CTextFieldSet::NewL(const MTextFieldFactory* aFactory,const CStreamStore& aFieldStore,TStreamId aStreamId)
+	{
+	CTextFieldSet* self=new(ELeave) CTextFieldSet();
+	CleanupStack::PushL(self);
+	self->SetFieldFactory(CONST_CAST(MTextFieldFactory*,aFactory));
+	self->ConstructL(0);
+	self->DoRestoreL(aFieldStore,aStreamId);
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+CTextFieldSet::CTextFieldSet()
+	{}
+
+
+void CTextFieldSet::ConstructL(TInt aDocumentLength)
+// Creates an array in which to store all fields
+// Inserts an initial entry into the array to cover any text that lies after the last field
+//
+	{
+	iFieldArray = new(ELeave) CArrayFixSeg<TTextFieldEntry>(KFieldArrayGranularity);
+	AddInitialFieldEntryL(iFieldArray,aDocumentLength);
+
+	__TEST_INVARIANT;
+	}
+
+
+EXPORT_C CTextFieldSet::~CTextFieldSet()
+	{
+	delete iRollbackInfo;
+	if (iFieldArray)
+		{
+		TInt fieldCount=iFieldArray->Count();
+		for (TInt index=fieldCount-1;index>=0;index--)
+			delete (*iFieldArray)[index].iFieldHeader.iField.AsPtr(); // Delete the textField objects
+		delete iFieldArray;
+		}
+	}
+
+
+EXPORT_C void CTextFieldSet::SetFieldFactory(MTextFieldFactory* aFactory)
+	{
+	iFieldFactory = aFactory;
+	}
+
+
+EXPORT_C MTextFieldFactory* CTextFieldSet::FieldFactory()const
+	{
+	return iFieldFactory;
+	}
+
+
+void CTextFieldSet::InsertEntryL(TInt aIndex,TTextFieldEntry& aEntry)
+	{
+	InsertEntryL(aIndex,aEntry,iFieldArray);
+	}
+
+
+void CTextFieldSet::InsertEntryL(TInt aIndex,TTextFieldEntry& aEntry,CArrayFixSeg<TTextFieldEntry>* aArray)
+// if this function leaves it will be as if it had never been called...
+//
+	{
+	if (aEntry.iFieldHeader.iField.IsPtr())
+		CleanupStack::PushL(aEntry.iFieldHeader.iField.AsPtr());
+	aArray->InsertL(aIndex,aEntry); // insert new entry
+	if (aEntry.iFieldHeader.iField.IsPtr())
+		CleanupStack::Pop();
+	}
+
+
+void CTextFieldSet::AppendEntryL(TTextFieldEntry& aEntry)
+	{
+	AppendEntryL(aEntry,iFieldArray);
+	}
+
+
+void CTextFieldSet::AppendEntryL(TTextFieldEntry& aEntry,CArrayFixSeg<TTextFieldEntry>* aArray)
+	{
+	if (aEntry.iFieldHeader.iField.IsPtr())
+		CleanupStack::PushL(aEntry.iFieldHeader.iField.AsPtr());
+	aArray->AppendL(aEntry); // insert new entry
+	if (aEntry.iFieldHeader.iField.IsPtr())
+		CleanupStack::Pop();
+	}
+
+
+TInt CTextFieldSet::EntryLen(TInt aIndex)const
+	{
+	return EntryLen((*iFieldArray)[aIndex]);
+	}
+
+
+TInt CTextFieldSet::EntryLen(const TTextFieldEntry& aEntry)const
+	{
+	return aEntry.iPreFieldLen+aEntry.iFieldValueLen;
+	}
+
+
+TTextFieldEntry CTextFieldSet::SplitEntry(TInt aIndex,TInt aOffset, TInt aRange)const
+// Splits the entry aIndex, returning the part demarked by the offset (from the start of the entry) and the range
+//
+	{
+	__TEST_INVARIANT;
+
+	__ASSERT_DEBUG((aIndex>=0)&&(aIndex<iFieldArray->Count()),Panic(EIndexOutOfRange));
+	TInt entryLength = EntryLen(aIndex);
+	__ASSERT_DEBUG((aOffset>=0)&&(aOffset<=entryLength),Panic(EPosOutOfRange));
+	__ASSERT_DEBUG((aRange>=0),Panic(ENegativeRange));
+
+	if ((aOffset+aRange)>entryLength)
+		aRange = entryLength-aOffset; // scale range down to entry size if neccessary
+
+	if ((aOffset==0)&&(aRange==entryLength))
+		return (*iFieldArray)[aIndex]; //entry does not need to be split
+
+	TInt charsCopied=0;
+	TTextFieldEntry entry;
+	entry.iPreFieldLen = 0;
+	entry.iFieldValueLen = 0;
+	entry.iFieldHeader.iField = NULL;
+	if (aOffset<(*iFieldArray)[aIndex].iPreFieldLen)
+		{// At least some of the pre needs to be copied
+		entry.iPreFieldLen = (*iFieldArray)[aIndex].iPreFieldLen-aOffset;
+		if ((entry.iPreFieldLen)>aRange)
+			entry.iPreFieldLen = aRange;
+		charsCopied = entry.iPreFieldLen;
+		}
+
+	if (charsCopied<aRange)
+		{// more to do, so at least some of the field needs to be copied
+		if ((aOffset+aRange)==entryLength)
+			{// whole field in range so copy it
+			entry.iFieldValueLen = (*iFieldArray)[aIndex].iFieldValueLen;
+			entry.iFieldHeader = (*iFieldArray)[aIndex].iFieldHeader;
+			}
+		else
+			// only part of field in range so convert it to text
+			entry.iPreFieldLen += aRange-charsCopied;
+		}
+	return entry;
+	}
+
+
+void CTextFieldSet::AddInitialFieldEntryL(CArrayFixSeg<TTextFieldEntry>* aArray,TInt aDocumentLength)
+// Add initial entry
+	{
+	TTextFieldEntry initialEntry;
+	initialEntry.iPreFieldLen = aDocumentLength;
+	initialEntry.iFieldValueLen = 0;
+	initialEntry.iFieldHeader.iFieldType = KNullUid;
+	initialEntry.iFieldHeader.iField = NULL;
+	aArray->AppendL(initialEntry);
+	}
+
+
+EXPORT_C void CTextFieldSet::Reset()
+// deletes all fields (but not corresponding text) and reinitialises the field array
+//
+	{
+	__TEST_INVARIANT;
+
+	for (TInt index=FieldCount()-1 ; index>=0 ; index--)
+		delete (*iFieldArray)[index].iFieldHeader.iField.AsPtr(); // Delete the textField objects
+	iFieldArray->Reset();
+	AddInitialFieldEntryL(iFieldArray,0); // cannot leave in this context
+	iFieldArray->Compress(); // compress array
+
+	__TEST_INVARIANT;
+	}
+
+
+EXPORT_C CTextField* CTextFieldSet::NewFieldL(TUid aFieldType)
+	{
+	if (iFieldFactory)
+		return iFieldFactory->NewFieldL(aFieldType);
+	else
+		return NULL;
+	}
+
+
+EXPORT_C TInt CTextFieldSet::InsertFieldL(TInt aPos,CTextField* aField,TUid aFieldType)
+// Inserts a field header aField at aPos (aField should be declared on the heap)
+// The field initially has zero length: Update must be called afterward
+//
+	{
+	__TEST_INVARIANT;
+	__ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc));
+	__ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
+	__ASSERT_ALWAYS(aField,Panic(ENoTextField));
+
+	TInt errLevel=KErrAlreadyExists;
+	TTextFieldEntry entry;
+	entry.iFieldHeader.iField = aField;
+	entry.iFieldHeader.iFieldType = aFieldType;
+	entry.iFieldValueLen = 0;
+	TInt index; TInt offset;
+	TBool inField = InField(aPos,index,offset);
+	if (!inField)
+		{// not inserting into a field
+		entry.iPreFieldLen = offset;
+		iFieldArray->InsertL(index,entry); // insert new entry
+		(*iFieldArray)[index+1].iPreFieldLen -= offset; // update old entry
+		errLevel = KErrNone;
+		}
+	else if (offset==0)
+		{// at start of field
+		entry.iPreFieldLen = (*iFieldArray)[index].iPreFieldLen;
+		iFieldArray->InsertL(index,entry); // insert new entry
+		(*iFieldArray)[index+1].iPreFieldLen = 0; // update old entry
+		errLevel = KErrNone;
+		}
+
+	__TEST_INVARIANT;
+	return errLevel;
+	}
+
+
+EXPORT_C const CTextField* CTextFieldSet::TextField(TInt aPos)const
+// Return a handle to the concrete field at document position aPos.
+// Returns NULL if there is no field at position aPos.
+//
+	{
+	__TEST_INVARIANT;
+
+	TInt index=-1;
+	TInt offset=0;
+	TBool inField=InField(aPos,index,offset);
+	if (!inField)
+		return NULL;
+	TSwizzle<CTextField> field=(*iFieldArray)[index].iFieldHeader.iField;
+	__ASSERT_DEBUG(field.IsPtr(),User::Invariant());
+	return field.AsPtr();
+	}
+
+
+EXPORT_C TInt CTextFieldSet::RemoveField(TInt aPos)
+// Removes the field from the array, adding it's content to the "before" of the next field.
+// After this function is called the text the field contained should be deleted. If this does
+//   not happen this function acts as a "ConvertFieldToText()"
+//
+	{
+	__TEST_INVARIANT;
+	__ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc));
+	__ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
+
+	TInt errLevel=KErrNone;
+	TInt index; TInt offset;
+	if (!InField(aPos,index,offset))
+		errLevel = KErrNotFound;
+	else
+		// delete the field entry tidily
+		DeleteFieldEntry(index);
+
+	__TEST_INVARIANT;
+	return errLevel;
+	}
+
+
+EXPORT_C TInt CTextFieldSet::FieldCount() const
+	{
+	__TEST_INVARIANT;
+
+	// return count-1 because there is always an entry in the array for the text at the
+	//  end of the document, after the last field (maybe just the end of doc char)
+	return (iFieldArray->Count()-1);
+	}
+
+
+EXPORT_C TInt CTextFieldSet::CharCount() const
+// returns the number of characters in the document according to the field array
+	{
+	__TEST_INVARIANT;
+
+	TInt charCount = 0;
+	for (TInt index=FieldCount() ; index>=0 ; index--)
+		charCount += (*iFieldArray)[index].iPreFieldLen+(*iFieldArray)[index].iFieldValueLen;
+	return charCount;
+	}
+
+
+EXPORT_C TBool CTextFieldSet::FindFields(TInt aPos) const
+// Return ETrue if aPos is in a field
+//
+	{
+	TFindFieldInfo dummy;
+	return (FindFields(dummy,aPos,0));
+	}
+
+
+EXPORT_C TBool CTextFieldSet::FindFields(TFindFieldInfo& aInfo,TInt aPos, TInt aRange) const
+// Check whether aPos is in a field, then check whether any fields start in aRange
+//
+	{
+	__TEST_INVARIANT;
+	__ASSERT_ALWAYS(aRange>=0,Panic(ENegativeRange));
+	__ASSERT_ALWAYS(aPos>=0,Panic(EPosOutsideDoc));
+	__ASSERT_ALWAYS(aPos+aRange<=CharCount(),Panic(EPosOutsideDoc));
+	
+	aInfo.iFieldCountInRange = 0;
+	aInfo.iFirstFieldLen = 0;
+	aInfo.iFirstFieldPos = 0;
+	TInt pos=aPos; // position in doc
+	// are we in a field to begin with?
+	TInt index; TInt offset;
+	if (InField(aPos,index,offset)) 
+		{
+		aInfo.iFieldCountInRange++;
+		aInfo.iFirstFieldLen = (*iFieldArray)[index].iFieldValueLen;
+		aInfo.iFirstFieldPos = aPos-offset;
+		pos += (*iFieldArray)[index].iFieldValueLen-offset+(*iFieldArray)[index+1].iPreFieldLen;
+		index++;
+		}
+	else
+		pos += (*iFieldArray)[index].iPreFieldLen-offset;
+	// step through array until aRange
+	while (pos<aPos+aRange)
+		// When entering this loop we're always at the beginning of a field value
+		// set aFieldEntry to first field found (if fieldcount==0)
+		// for each start of field encountered, fieldCount++
+		{
+		if (aInfo.iFieldCountInRange==0)
+			{
+			aInfo.iFirstFieldLen = (*iFieldArray)[index].iFieldValueLen;
+			aInfo.iFirstFieldPos = pos;
+			}
+		aInfo.iFieldCountInRange++;
+		pos += (*iFieldArray)[index].iFieldValueLen+(*iFieldArray)[index+1].iPreFieldLen;
+		index++;
+		}
+	// (if sensing right) check that we haven't ended adjacent to one or more zero-length fields 
+	if ( (aRange==0) && (pos==aPos) && (index<(iFieldArray->Count()-1)) && ((*iFieldArray)[index].iFieldValueLen==0) )
+		{
+		aInfo.iFieldCountInRange++;
+		index++;
+		while ( ((*iFieldArray)[index].iPreFieldLen==0) && ((*iFieldArray)[index].iFieldValueLen==0) && (index<(iFieldArray->Count()-1)) )
+			{
+			aInfo.iFieldCountInRange++;
+			index++;
+			}
+		}
+
+	__ASSERT_DEBUG(aInfo.iFieldCountInRange<=FieldCount(),Panic(EDebug));
+	return aInfo.iFieldCountInRange;
+	}
+
+
+EXPORT_C TInt CTextFieldSet::NewFieldValueL(HBufC*& aBuf, TInt aPos)
+// Returns the new value of the field at aPos (if applicable).
+// The method might reallocate aBuf parameter, so don't forget to:
+// 1) Push aBuf parameter in the CleanupStack before the call. The call
+//      may fail, then aBuf gets lost.
+// 2) Pop aBuf parameter from the CleanupStack after the call - aBuf may get
+//      reallocated, so the pushed pointer becomes invalid.
+// 3) Push aBuf in the CleanupStack again.
+	{
+	__TEST_INVARIANT;
+	__ASSERT_ALWAYS(aBuf,Panic(ENoBuffer));
+	__ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc));
+	__ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
+	
+	TInt errLevel = KErrNotFound;
+	TInt index; TInt offset;
+	if (InField(aPos,index,offset))
+		{// There's a field at aPos
+		TPtr bufPtr = aBuf->Des();
+		TInt reqLen = (*iFieldArray)[index].iFieldHeader.iField->Value(bufPtr);
+		while (reqLen>0)
+			{// If more storage is required for the value then reallocate the buffer
+			aBuf = aBuf->ReAllocL(reqLen); // for unicode compatability, rounds up
+			TPtr pointer = aBuf->Des();
+			reqLen = (*iFieldArray)[index].iFieldHeader.iField->Value(pointer);
+			}
+		// dont set new field length - this will be done in a subsequent NotifyInsert()
+		errLevel = KErrNone;
+		}
+
+	__TEST_INVARIANT;
+	return errLevel;
+	}
+
+
+EXPORT_C void CTextFieldSet::NotifyInsertion(TInt aPos, TInt aNumberAdded)
+// Informs the array that aNumberAdded characters have been inserted in the document
+//
+	{
+	__TEST_INVARIANT;
+	__ASSERT_ALWAYS(aPos>=0,Panic(EPosOutsideDoc));
+	__ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
+	__ASSERT_ALWAYS(aNumberAdded>=0,Panic(EIllegalNegativeValue));
+
+	TInt index; TInt offset;
+	// are the extra characters in a field (matching away from fields)?
+	if (!InField(aPos,index,offset))
+		(*iFieldArray)[index].iPreFieldLen += aNumberAdded;
+	else
+		if (offset>0)
+			(*iFieldArray)[index].iFieldValueLen += aNumberAdded;
+		else
+			(*iFieldArray)[index].iPreFieldLen += aNumberAdded;
+
+	__TEST_INVARIANT;
+	}                             
+
+
+EXPORT_C void CTextFieldSet::NotifyFieldUpdate(TInt aPos, TInt aNewFieldValueLength)
+	{
+	__TEST_INVARIANT;
+	__ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc));
+	__ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
+	__ASSERT_ALWAYS(aNewFieldValueLength>=0,Panic(EIllegalNegativeValue));
+
+	// Is the insert pos in a field? If so which?
+	TInt index; TInt offset;
+	__ASSERT_ALWAYS(InField(aPos,index,offset),Panic(EPosNotInField));
+	// Update the length of the relevant field
+	(*iFieldArray)[index].iFieldValueLen = aNewFieldValueLength;
+	
+	__TEST_INVARIANT;
+	}
+
+
+EXPORT_C void CTextFieldSet::NotifyDeletion(TInt aPos,TInt aTotalRemoved)
+// Informs the array that aTotalRemoved characters have been removed from the document
+// Any fields wholely contained will be removed, those partially intersecting will just be shortened
+//
+	{
+	__TEST_INVARIANT;
+	__ASSERT_ALWAYS(aPos>=0,Panic(EPosOutsideDoc));
+	__ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
+	__ASSERT_ALWAYS(aTotalRemoved>=0,Panic(EIllegalNegativeValue));
+	
+	TInt charCount = CharCount();
+	
+	//There is a possibility that there exists hidden end-of-document character in rich text objects.
+	//This is checked by the if statement & accordingly aTotalRemoved is decremented.
+	//i.e. aPos + aTotalRemoved could be greater by 1 than the CharCount(),  
+	//this is because the aTotalRemoved might also include 1 hidden character. - DEF095911
+	if(aPos+aTotalRemoved > charCount)
+		aTotalRemoved--;
+
+	__ASSERT_DEBUG(aPos+aTotalRemoved<=charCount, Panic(EPosOutsideDoc));
+
+	int index = 0;
+	int offset = 0;
+	int cur_pos = aPos;
+	int end_pos = aPos + aTotalRemoved;
+	TBool in_field = InField(cur_pos,index,offset);
+	TTextFieldEntry* field = NULL;
+	int field_start = 0;
+	int field_end = 0;
+	if (index >= 0 && index < iFieldArray->Count())
+		{
+		field = &(*iFieldArray)[index];
+		field_start = cur_pos - offset;
+		if (!in_field)
+			field_start += field->iPreFieldLen;
+		field_end = field_start + field->iFieldValueLen;
+		}
+
+	while (field)
+		{
+		// Reduce the size of the gap before the field if any.
+		int gap = Min(end_pos,field_start) - cur_pos;
+		if (gap > 0)
+			{
+			cur_pos += gap;
+			field->iPreFieldLen -= gap;
+			}
+		if (cur_pos >= end_pos)
+			break;
+
+		// Reduce the field length.
+		int remove_start = cur_pos;
+		int remove_end = Min(field_end,end_pos);
+		cur_pos = field_end;
+		field->iFieldValueLen -= (remove_end - remove_start);
+
+		// Delete the field if it is now of zero length.
+		int added_to_next = 0;
+		if (field->iFieldValueLen == 0)
+			{
+			added_to_next = field->iPreFieldLen;
+			DeleteFieldEntry(index);
+			}
+		else
+			index++;
+
+		// Move to the next field.
+		if (index < iFieldArray->Count())
+			{
+			field = &(*iFieldArray)[index];
+			field_start = cur_pos + field->iPreFieldLen - added_to_next;
+			field_end = field_start + field->iFieldValueLen;
+			}
+		else
+			field = NULL;
+		}
+
+	__TEST_INVARIANT;
+	}
+
+
+TBool CTextFieldSet::InField(const TInt aPos, TInt& anIndex, TInt& anOffset) const
+// works out whether or not aPos is in a field (matching right),
+//  sets anIndex to the index number of the field entry,
+//  and sets anOffset to the distance aPos is into the field or its preceeding gap
+//
+	{
+	__ASSERT_ALWAYS((aPos>=0),Panic(EPosOutsideDoc));
+	__ASSERT_DEBUG(aPos<=CharCount(),Panic(EPosOutsideDoc));
+
+	TBool inField;
+	TInt currentPos = 0;
+	anIndex = 0;
+	TInt lengthOfDoc = CharCount();
+	TInt lastFieldNum = iFieldArray->Count()-1;
+	// Find the index of the entry containing aPos
+	if (aPos == lengthOfDoc)
+		{
+		anIndex = lastFieldNum;
+		currentPos = aPos;
+		}
+	else 
+		{
+		anIndex = -1;
+		while (aPos >= currentPos)
+			{
+			anIndex++;
+			currentPos += (*iFieldArray)[anIndex].iPreFieldLen+(*iFieldArray)[anIndex].iFieldValueLen;
+			}
+		}
+	// Check that we have not skipped over any zero-length fields
+	if ( ((anIndex-1)>=0) && ((*iFieldArray)[anIndex-1].iFieldValueLen==0) )
+		{
+		TInt temp = currentPos - ((*iFieldArray)[anIndex].iPreFieldLen+(*iFieldArray)[anIndex].iFieldValueLen);
+		if (temp==aPos)
+			{// aPos is on a field boundary
+			currentPos = temp;
+			anIndex--;
+			while ( ((anIndex-1)>=0)
+				&&((*iFieldArray)[anIndex].iPreFieldLen==0)
+				&&((*iFieldArray)[anIndex-1].iFieldValueLen==0) )
+				{
+				anIndex--;
+				}
+			}
+		}
+	// Move to the start of the field (end of prefield) in entry [anIndex]
+	currentPos -= (*iFieldArray)[anIndex].iFieldValueLen;
+	// Determine whether or not aPos is in the field of entry[anIndex]
+	if (anIndex == lastFieldNum)
+		inField = EFalse;
+	else if (aPos >= currentPos)
+			inField = ETrue;
+		else
+			inField = EFalse;
+	// Calculate the offset
+	if (inField)
+		anOffset = aPos-currentPos;
+	else
+		anOffset = aPos+(*iFieldArray)[anIndex].iPreFieldLen-currentPos;
+	return inField;
+	}
+
+
+void CTextFieldSet::DeleteFieldEntry(TInt anIndex)
+	{
+	DeleteFieldEntry(iFieldArray,anIndex);
+	}
+
+
+void CTextFieldSet::DeleteFieldEntry(CArrayFixSeg<TTextFieldEntry>* aArray,TInt anIndex)
+// remove the entry anIndex from the array but don't delete the text from the doc.
+//
+	{
+	__ASSERT_ALWAYS(anIndex<(aArray->Count()-1),Panic(EIndexOutOfRange));
+
+	// add the entry's "before" to the "before" of the next entry.
+	(*aArray)[anIndex+1].iPreFieldLen += (*aArray)[anIndex].iPreFieldLen;
+	// add the field's length to the "before" of the next entry.	
+	(*aArray)[anIndex+1].iPreFieldLen += (*aArray)[anIndex].iFieldValueLen;
+	if ((*aArray)[anIndex].iFieldHeader.iField.IsPtr())
+		delete (*aArray)[anIndex].iFieldHeader.iField.AsPtr(); // delete the field
+	aArray->Delete(anIndex); // remove the entry from the array
+	}
+
+
+///////////////////////////////////////////////
+// TTextFieldEntry
+///////////////////////////////////////////////
+
+
+EXPORT_C void TTextFieldEntry::InternalizeL(RReadStream& aStream)
+// entry must have a header (ie cant be last entry in the array)
+	{
+	iPreFieldLen = aStream.ReadInt32L();
+	iFieldValueLen = aStream.ReadInt32L();
+	aStream>> iFieldHeader;
+	}
+
+
+EXPORT_C void TTextFieldEntry::ExternalizeL(RWriteStream& aStream)const
+// entry must have a header (ie cant be last entry in the array)
+	{
+	aStream.WriteInt32L(iPreFieldLen);
+	aStream.WriteInt32L(iFieldValueLen);
+	aStream<< iFieldHeader;
+	}
+
+