// CHTTPFormEncoder.cpp
// 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 <chttpformencoder.h> // Class signature
#include <httperr.h>
// Local includes
const TInt KFormEncoderBufferIncrementSize = 256;
EXPORT_C CHTTPFormEncoder* CHTTPFormEncoder::NewL()
{
CHTTPFormEncoder* self = new (ELeave) CHTTPFormEncoder();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
EXPORT_C CHTTPFormEncoder::~CHTTPFormEncoder()
{
__ASSERT_DEBUG(iState != ESupplyingData,HTTPPanic::Panic(HTTPPanic::EHTTPFormDataUnreleased));
delete iData;
}
CHTTPFormEncoder::CHTTPFormEncoder()
{}
void CHTTPFormEncoder::ConstructL()
{
iData = HBufC8::NewL(KFormEncoderBufferIncrementSize);
}
TBool CHTTPFormEncoder::GetNextDataPart(TPtrC8& aDataPart)
{
aDataPart.Set(*iData);
iState = ESupplyingData;
return ETrue;
}
void CHTTPFormEncoder::ReleaseData()
{
iState = EDataReleased;
}
TInt CHTTPFormEncoder::OverallDataSize()
{
iState = ESuppliedSize;
return iData->Size();
}
TInt CHTTPFormEncoder::Reset()
{
iState = EAllowAppendData;
return KErrNone;
}
EXPORT_C void CHTTPFormEncoder::AddFieldL(const TDesC8& aFieldName, const TDesC8& aFieldValue)
{
__ASSERT_DEBUG(iState==EAllowAppendData, HTTPPanic::Panic(HTTPPanic::EHTTPFormSupplyingData));
if (!aFieldName.Length())
User::Leave(KErrArgument);
// The maximum size is if every single character would have to be encoded as its hex equivalent.
// That is %HH. Also need to add room for the '=' and '&' field separator
TInt reqSize = (aFieldName.Length() + aFieldValue.Length())*3 +2;
if (!iData)
iData = HBufC8::NewL(reqSize);
else
{
TInt currentLength = iData->Length();
if (reqSize + currentLength > iData->Des().MaxLength())
{
TInt amountToGrow = reqSize < KFormEncoderBufferIncrementSize? KFormEncoderBufferIncrementSize : reqSize;
iData = iData->ReAllocL(amountToGrow+currentLength);
}
}
if (iData->Length() >0)
iData->Des().Append('&');
AppendData(aFieldName);
iData->Des().Append('=');
AppendData(aFieldValue);
}
TBool CHTTPFormEncoder::IsAlphaNumeric(TUint8 aChar)
{
return (aChar >= 'a' && aChar <= 'z') ||
(aChar >= 'A' && aChar <= 'Z') ||
(aChar >= '0' && aChar <='9');
}
/** Appends a non alpha numeric character by converting it to %HH where HH is the Hexadecmial representation
of the character
*/
void CHTTPFormEncoder::AppendSpecialChar(TUint8 aChar)
{
TPtr8 dataPtr = iData->Des();
dataPtr.Append('%');
TUint hexChar = aChar/16;
hexChar = hexChar > 9 ? hexChar + 55 : hexChar + 48;
dataPtr.Append(hexChar);
hexChar= aChar%16;
hexChar = hexChar > 9 ? hexChar + 55 : hexChar + 48;
dataPtr.Append(hexChar);
}
void CHTTPFormEncoder::AppendData(const TDesC8& aData)
{
TBool hadCR = EFalse;
TInt length = aData.Length();
for (TInt ii=0; ii<length; ++ii)
{
TPtr8 dataPtr = iData->Des();
TUint8 charToProcess = aData[ii];
if (charToProcess == 0x0d) // turn CR into CR/LF
{
hadCR = ETrue;
AppendSpecialChar(charToProcess);
AppendSpecialChar(0x0a);
continue;
}
if (hadCR)
{
hadCR = EFalse;
if (charToProcess == 0x0a) // LF after a CR, so skip as already appended
continue;
}
// handle spaces -> become +
if (charToProcess == ' ')
dataPtr.Append('+');
// handle normal character
else if (IsAlphaNumeric(charToProcess))
dataPtr.Append((TChar)charToProcess);
else
AppendSpecialChar(charToProcess); // encode to %HH
//
}
}