applayerprotocols/httptransportfw/core/CHeaderField.cpp
changeset 0 b16258d2340f
child 11 8f055b80aa5b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerprotocols/httptransportfw/core/CHeaderField.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,460 @@
+// Copyright (c) 2001-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:
+//
+
+// System includes
+#include <e32std.h>
+#include <http/framework/cheadercodec.h>
+
+// Local includes
+#include "CHeaders.h"
+
+// Class signature
+#include "CHeaderField.h"
+
+
+CHeaderField* CHeaderField::NewL(RStringF aHeaderFieldName, CHeaders& aOwner)
+	{
+	return new(ELeave)CHeaderField(aHeaderFieldName, aOwner);
+	}
+
+CHeaderField* CHeaderField::New(RStringF aHeaderFieldName, CHeaders& aOwner)
+    {
+    return new CHeaderField(aHeaderFieldName, aOwner);
+    }
+
+
+CHeaderField* CHeaderField::NewL(RStringF aHeaderFieldName, CHeaders& aOwner, THTTPHdrVal aVal)
+	{
+	CHeaderField* me = new(ELeave)CHeaderField(aHeaderFieldName, aOwner);
+	CleanupStack::PushL(me);
+	CHeaderFieldPart* part = CHeaderFieldPart::NewL(aVal);
+	CleanupStack::PushL(part);
+	me->AddPartL(part);
+	CleanupStack::Pop(2);
+	return me;
+	}
+
+
+CHeaderField* CHeaderField::NewL(RStringF aHeaderFieldName, CHeaders& aOwner, const TDesC8& aRawData)
+	{
+	CHeaderField* me = new(ELeave)CHeaderField(aHeaderFieldName, aOwner);
+	CleanupStack::PushL(me);
+	me->ConstructL(aRawData);
+	CleanupStack::Pop(me);
+	return me;
+	}
+
+
+/** D'tor
+*/
+
+CHeaderField::~CHeaderField()
+	{
+	iName.Close();
+	ClearParsedData();
+	ClearRawData();
+	iElementArray.Close();	
+	iParameterArray.Close();
+	}
+
+
+
+
+TInt CHeaderField::NumPartsL()
+	{
+	// Convert, if necessary, to the parsed format
+	ConvertToParsedFormatL();
+
+	// Check the array exists first
+	return iParts.Count();
+	}
+
+
+THeaderFieldPartIter CHeaderField::PartsL()
+	{
+	// Convert, if necessary, to the parsed format
+	ConvertToParsedFormatL();
+
+	// create an iterator initialised for this header
+	return THeaderFieldPartIter(this);
+	}
+
+TInt CHeaderField::Part(TInt aIndex, CHeaderFieldPart*& aPart)
+    {
+    TInt err = KErrNone;
+    // Check, is already in parsed format
+    if (iDataParseState == EDataInRawForm)
+        {
+        // Convert, to the parsed format
+        TRAP(err, ConvertToParsedFormatL());        
+        }        
+
+    if(err == KErrNone && aIndex < iParts.Count() && (aIndex >= 0))
+        {
+        aPart = iParts[aIndex];
+        }
+    return err;
+    }
+
+
+CHeaderFieldPart* CHeaderField::PartL(TInt aIndex)
+	{
+	// Convert, if necessary, to the parsed format
+	ConvertToParsedFormatL();
+
+	// Check the part is in range, if so return it
+	if ((aIndex < NumPartsL()) && (aIndex >= 0))
+		return iParts[aIndex];
+	else
+		return NULL;
+	}
+
+EXPORT_C
+void CHeaderField::RawDataL(TPtrC8& aRawData)
+	{
+	ConvertToRawFormatL();
+	aRawData.Set(*iRawData);
+	}
+
+
+/** Setters
+*/
+
+void CHeaderField::SetPartL(CHeaderFieldPart* aPart, TInt aIndex)
+	{
+	if (aIndex < iParts.Count())
+		{
+		CHeaderFieldPart* oldPart = iParts[aIndex];
+		iParts[aIndex] = aPart;
+		delete oldPart;
+		}
+	else
+		User::LeaveIfError(iParts.Append(aPart));
+	}
+
+void CHeaderField::BeginRawDataL(TInt aChunkSize)
+	{
+	iRawChunkSize = aChunkSize;
+
+	// clear out any existing Raw data, but don't reallocate if not needed
+	if (!iRawData)
+		iRawData = HBufC8::NewL(iRawChunkSize);
+	else
+		{
+		TPtr8 rawPtr = iRawData->Des();
+		rawPtr.Zero();
+		}
+	}
+
+
+void CHeaderField::WriteRawDataL(const TDesC8& aData)
+	{
+    // Check to see if the buffer needs to grow
+	TInt maxLength  = iRawData->Des().MaxLength();
+	TInt reqdLength = iRawData->Length() + aData.Length();
+	if (reqdLength > maxLength)
+		{
+		// Yes - allocate a new buffer of a larger size, and copy the contents
+		// of the old one over. This may need more than one extra chunk. Check
+		// for partial chunks - add an extra one if necessary.
+		TInt numChunksReqd = (reqdLength - maxLength)/iRawChunkSize;
+		 if ( (reqdLength - maxLength)%iRawChunkSize > 0)
+			++numChunksReqd;
+		HBufC8* largerBuffer = iRawData->ReAllocL(maxLength + iRawChunkSize*numChunksReqd);
+
+		// Switch buffers. The old one was removed by ReAlloc.
+		iRawData = largerBuffer;
+		}
+
+	// Can now append confidently
+	iRawData->Des().Append(aData);
+	}
+
+
+void CHeaderField::WriteRawDataL(TChar aData)
+	{
+	// Check to see if the buffer descriptor needs to grow
+	TInt maxLength  = iRawData->Des().MaxLength();
+	TInt reqdLength = iRawData->Length() + 1;
+	if (reqdLength > maxLength)
+		{
+		// Yes - allocate a new buffer of a larger size, and copy the contents
+		// of the old one over. Since a single character is being added, one
+		// chunk will be enough.
+		HBufC8* largerBuffer = iRawData->ReAllocL(maxLength + iRawChunkSize);
+
+		// Switch buffers. The old one was removed by ReAlloc.
+		iRawData = largerBuffer;
+		}
+
+	// Can now append confidently
+	iRawData->Des().Append(aData);
+	}
+
+
+void CHeaderField::CommitRawData()
+	{
+	// Change state and remove the parsed form of the header data
+	iDataParseState = EDataInRawForm;
+	ClearParsedData();
+	}
+
+
+void CHeaderField::AddPartL(CHeaderFieldPart* aPart)
+	{
+	// Convert, if necessary, to the parsed format
+	ConvertToParsedFormatL();
+
+	// Append the item
+	User::LeaveIfError(iParts.Append(aPart));
+	}
+
+TInt CHeaderField::AddPart(CHeaderFieldPart* aPart)
+    {
+    TInt err = KErrNone;
+    if (iDataParseState == EDataInRawForm)
+        {
+        TRAP(err, AddPartL(aPart));
+        }
+    if(err == KErrNone)
+        {
+        err = iParts.Append(aPart);
+        }
+    return err;
+    }
+
+void CHeaderField::InsertPartL(CHeaderFieldPart* aPart, TInt aIndex)
+	{
+	// Convert, if necessary, to the parsed format
+	ConvertToParsedFormatL();
+
+	// If the array isn't yet constructed, or is empty, then use 'AddPart'
+	if (!NumPartsL()) 
+		AddPartL(aPart);
+	else
+		User::LeaveIfError(iParts.Insert(aPart, aIndex));
+	}
+
+
+TInt CHeaderField::RemovePartL(CHeaderFieldPart* aPart)
+	{
+	// Convert, if necessary, to the parsed format
+	ConvertToParsedFormatL();
+
+	// Sanity check - if no parts, then the part can't be removed...
+	if (iParts.Count() == 0)
+		return KErrNotFound;
+
+	// Find the part.  
+	TInt idx = iParts.Find(aPart);
+
+	// Now remove by index
+	iParts.Remove(idx);
+	iParts.Compress();
+	delete aPart;
+	return KErrNone;
+	}
+
+
+TInt CHeaderField::RemovePartL(TInt aIndex)
+	{
+	// Convert, if necessary, to the parsed format
+	ConvertToParsedFormatL();
+
+	// Sanity check - if no array exists or if the index supplied is out of the bounds
+	// of the array, then the part can't be removed...
+	if ((aIndex < 0) || (aIndex >= NumPartsL()))
+		return KErrNotFound;
+
+	// Note that the array doesn't actually delete the part itself. Also the array must be
+	// compressed to close the 'gap' left by the deleted part
+	CHeaderFieldPart* part = PartL(aIndex);
+	iParts.Remove(aIndex);
+	iParts.Compress();
+	delete part;
+	return KErrNone;
+	}
+
+
+/** Constructors and second-phase construction
+*/
+
+void CHeaderField::ConvertToRawFormatL()
+	{
+	if (iDataParseState != EDataParsedOK)
+		return;
+	RHeaderField rf(*this);
+	// State change and removal of parsed data  is done when the Raw data is committed by the codec when it is encoded
+	iCodec.EncodeHeaderL(rf);
+	}
+
+void CHeaderField::ConvertToParsedFormatL()
+	{
+	if (iDataParseState != EDataInRawForm)
+		return;
+	RHeaderField rf(*this);
+	iCodec.DecodeHeaderL(rf);
+
+	// If we haven't left, then it must have succeeded. Change state and remove the Raw data
+	iDataParseState = EDataParsedOK;
+	ClearRawData();
+	}
+
+TInt CHeaderField::ConvertToParsedFormat()
+    {
+    if (iDataParseState != EDataInRawForm)
+        return KErrNone;
+
+    RHeaderField rf(*this);
+    TRAPD(err, iCodec.DecodeHeaderL(rf));
+    if(err != KErrNone)
+        return err;
+
+    // If we haven't left, then it must have succeeded. Change state and remove the Raw data
+    iDataParseState = EDataParsedOK;
+    ClearRawData();
+
+    return KErrNone;
+    }
+
+TInt CHeaderField::SplitValueAndParameterArray()
+    {
+    const TUint count = iParts.Count();
+    CHeaderFieldPart* part = NULL;
+    TInt ret = KErrNone;
+    for(TUint i = 0; (i < count) && (ret == KErrNone); ++i)
+        {
+        part = iParts[i];
+        THTTPHdrVal val = part->Value();        
+        if(((val.Type() == THTTPHdrVal::KStrVal) && val.Str().DesC().Length() > 0) || 
+                ((val.Type() == THTTPHdrVal::KStrFVal) && val.StrF().DesC().Length() > 0))
+            {
+            ret = iElementArray.Append(part);
+            }
+        else
+            {
+            const TUint numParams = part->NumParameters();
+            if(numParams > 0)  // Push only if it has some parameters.
+                {
+                for(TUint j = 0; j < numParams && ret == KErrNone; ++j)
+                    {
+                    ret = iParameterArray.Append(part->Parameter(j));
+                    }
+                }
+            else
+                {
+                ret = iElementArray.Append(part);
+                }
+            }        
+        }
+    return ret;
+    }
+
+CHeaderField::CHeaderField(RStringF aHeaderFieldName, CHeaders& aOwner)
+	: iCodec(aOwner.Codec()), iDataParseState(ENoDataSupplied), iOwner(&aOwner) 
+	{
+	// Ensure that we maintain string references correctly with the header field name
+	iName = aHeaderFieldName.Copy();
+	iDataParseState = EDataParsedOK;
+	}
+
+void CHeaderField::ConstructL(const TDesC8& aRawData)
+	{
+	// Copy the data.  Set the state.
+	iRawData = aRawData.AllocL();
+	iDataParseState = EDataInRawForm;
+	}
+
+void CHeaderField::ClearParsedData()
+	{
+	// Clear and destroy parts array and its contents
+	iParts.ResetAndDestroy();
+	}
+
+void CHeaderField::ClearRawData()
+	{
+	// Destroy any Raw data
+	delete iRawData;
+	iRawData = NULL;
+	}
+
+
+/** Implementation of CHeaderFieldPart class *************************************************
+*/
+
+
+/** Getter's
+*/
+
+CHeaderFieldParam* CHeaderFieldPart::Parameter(RStringF aParamName) const
+	{
+	// Iterate the parameter list looking for a name match
+	THeaderFieldParamIter it(this);
+	CHeaderFieldParam* retVal = NULL;
+	const CHeaderFieldParam* nextParam = NULL;
+	TBool done = EFalse;
+	while (!done && !it.AtEnd())
+		{
+		nextParam = it();
+		if (nextParam && (nextParam->Name() == aParamName))
+			{
+			retVal = CONST_CAST(CHeaderFieldParam*, nextParam);
+			done = ETrue;
+			}
+		++it;
+		}
+	return retVal;
+	}
+
+
+
+/** Setter's
+*/
+
+
+void CHeaderFieldPart::SetValue(THTTPHdrVal aVal)
+	{
+	// We must check for an existing string value since it will have to be closed
+	if (iValue.Type() == THTTPHdrVal::KStrFVal)
+		iValue.StrF().Close();
+	if (iValue.Type() == THTTPHdrVal::KStrVal)
+		iValue.Str().Close();
+	iValue = aVal.Copy();
+	}
+
+
+
+TInt CHeaderFieldPart::RemoveParam(CHeaderFieldParam* aParam)
+	{
+	// Sanity check - if no array exists, then the part can't be removed...
+	if (iParams.Count() == 0)
+		return KErrNotFound;
+
+	// Find the param. 
+	TInt idx = iParams.Find(aParam);
+
+	// Now remove by index. Note that the array doesn't actually delete the param itself. Also
+	// the array must be compressed to close the 'gap' left by the deleted param
+	if (idx != KErrNotFound)
+		{
+		iParams.Remove(idx);
+		iParams.Compress();
+		delete aParam;
+		idx = KErrNone;
+		}
+	return idx;
+	}
+
+