genericservices/httputils/wspcodec/WSPEncoder.cpp
changeset 0 e4d67989cc36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/genericservices/httputils/wspcodec/WSPEncoder.cpp	Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,630 @@
+// 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:
+//
+
+#include <wspencoder.h>
+
+//constants
+//
+const TUint8 KWSPQuoteCharacter	= 0x7F; // QUOTE character as specified in the WSP BNF. 
+const TUint8 KWSPQuote			= 0x22; // The regular quote character ".
+const TUint8 KCarryBitMask		= 0x80; // Continue bit set
+#define KTopBitMask KCarryBitMask		// Mask for checking top bit
+const TUint KUintVarIndicator	= 31;	// Byte value indicating a UIntVar follows.
+const TUint KUIntVarOctetShift	= 7;	// Octet shift required processing a UnIntVar
+const TUint KLongIntOctetShift	= 8;	// Octet shift required processing a LongInt
+const TInt KDesArrayGranularity = 6;	// Granularity of descriptor array
+_LIT8(KWspStringTerminator, "\0");
+_LIT8(KTxtSeparators, "()<>@,;:\\\"/[]?={} "); // Separator characters as defined in RFC2616
+
+// Panic category
+//
+_LIT(KWspCodecPanicCategory,"WSPCODEC"); 
+
+/**
+	Static factory constructor.
+	
+	@leave			KErrNoMemory
+	@return		returns a Pointer to fully constructed CWspHeaderEncoder object.
+*/
+EXPORT_C CWspHeaderEncoder* CWspHeaderEncoder::NewL()
+	{
+	CWspHeaderEncoder* self = CWspHeaderEncoder::NewLC();
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+/**
+ 	Static factory constructor.
+	
+	@leave			KErrNoMemory
+	@return		returns a Pointer to fully constructed CWspHeaderEncoder object on the Heap.
+*/
+EXPORT_C CWspHeaderEncoder* CWspHeaderEncoder::NewLC()
+	{
+	CWspHeaderEncoder* self = new (ELeave) CWspHeaderEncoder();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+/** 
+	Default constructor. 
+*/
+CWspHeaderEncoder::CWspHeaderEncoder()
+	{
+	}
+	
+/**
+	 Default destructor
+*/
+EXPORT_C CWspHeaderEncoder::~CWspHeaderEncoder()			
+	{
+	iArray.ResetAndDestroy();
+	}
+
+/** 
+	Standard second phase construction. 
+*/
+void CWspHeaderEncoder::ConstructL()			
+	{
+	// Create new buffer;
+	CDesC8Array* buffer = new (ELeave) CDesC8ArrayFlat(KDesArrayGranularity);
+	CleanupStack::PushL(buffer);
+	User::LeaveIfError(iArray.Append(buffer));
+	CleanupStack::Pop(buffer);
+	}
+	
+/**
+  Starts a new encoded header. 
+ 
+  @param 			aToken	field name being encoded as a Token value.
+  @leave			KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::StartHeaderL(TUint8 aToken)			
+	{
+	__ASSERT_DEBUG(iTotalLength==0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderCalledTwice));
+	AddShortIntL(aToken);
+	}
+	
+/**
+  Starts a new encoded header.
+
+  @param 	aString	Fieldname parameter is encoded as a TextString.
+  @leave	KErrNoMemory
+*/	
+EXPORT_C void CWspHeaderEncoder::StartHeaderL(const TDesC8& aString)
+	{
+	__ASSERT_DEBUG(iTotalLength==0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderCalledTwice));
+	AddTextStringL(aString);
+	}
+
+/**
+  Starts a new encoded header.
+
+  @param 	aString	Fieldname parameter is encoded as a TextString.
+  @leave	KErrNotSupported
+*/
+EXPORT_C void CWspHeaderEncoder::StartHeaderL(const RStringF /* aString */ )
+	{
+	__ASSERT_DEBUG(iTotalLength==0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderCalledTwice));
+	User::Leave(KErrNotSupported);
+	}
+
+
+/**
+ 	Completes and returns encoded field 8 bit buffer. This method will panic if an 
+ 	EndValueLengthL() is not called after a StartValueLength().
+	
+	Note: 
+	The final buffer containing the entire encoded header is constructed.
+	Returns buffer containing the encoded field constructed 
+	from the first call to StartHeaderL. 
+					
+	@return		Pointer to buffer containing the entire encoded field.
+	 			Responsibility for deallocating the memory is also passed.
+	@pre 		The function StartHeaderL should have been called.
+	@post		Encoder is reset ready to be used again.
+	@leave		HBufC8::NewL leaves, if the new 8 bit heap descriptor cannot be created.
+
+*/
+EXPORT_C HBufC8* CWspHeaderEncoder::EndHeaderL()
+	{
+	__ASSERT_DEBUG(iArray.Count()==1,User::Panic(KWspCodecPanicCategory, EWspCodecPanicEndValueLengthNotCalled));
+	// concatenate array elements and return.
+
+	HBufC8* outputBuffer = HBufC8::NewL(iTotalLength);
+
+	CDesC8Array* desc = iArray[0];
+	TInt count = desc->Count();
+	for (TInt jj=0; jj<count; ++jj) 
+		{
+		(outputBuffer->Des()).Append((*desc)[jj]);
+		}
+
+	desc->Reset();
+	iTotalLength=0;
+	return outputBuffer;
+	}
+
+/**
+  Encodes input Integer value and adds it to the encoded field. Choice of encoded 
+  form dependent on the size of the input.Either ShortInt or LongInt method chosen.
+					
+  @param 		aInt	Integer value to be encoded.
+  @pre			StartHeaderL needs to have been called.
+  @leave		KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::AddIntegerL(const TUint aInt)
+	{
+	// Determine if its a short or longInt we want
+	(aInt < KTopBitMask) ? AddShortIntL((TUint8) aInt) : AddLongIntL(aInt);
+	}
+
+/**
+  Encodes input and adds it to the encoded field. Encodes parameter value using WSP 
+  ShortInt method.
+ 					
+  @param 			aValue	value to be encoded.
+  @pre				StartHeaderL needs to have been called.
+  @leave			KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::AddShortIntL(const TUint8 aValue)
+	{
+	const TInt arrayCount=iArray.Count();
+	__ASSERT_DEBUG(arrayCount>0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderLNotCalled));
+	CDesC8Array* desc=iArray[arrayCount-1];
+
+
+	// ShortInt shoud be a character 127 or less. With highest bit set to 1.
+	TUint8 shortInt = TWspPrimitiveEncoder::ShortInt(aValue);
+
+	desc->AppendL(TPtrC8(&shortInt, 1));
+	++iTotalLength;
+	}
+
+
+/**
+  Encodes input and adds it to the encoded field. For short length the value must
+  be between octet 0 - 31.
+ 	
+  @param 		aValue	value to be encoded.
+  @pre			StartHeaderL needs to have been called.
+  @leave		KErrNoMemory, KErrOverflow if the value is greater than 31
+*/
+EXPORT_C void CWspHeaderEncoder::AddShortLengthL(const TUint8 aValue)
+	{
+	const TInt arrayCount=iArray.Count();
+	__ASSERT_DEBUG(arrayCount>0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderLNotCalled));
+	CDesC8Array* desc=iArray[arrayCount-1];
+
+	// Check if the value is in the correct range ie octet 0-31
+	if(aValue > KUintVarIndicator)
+		User::Leave(KErrOverflow);
+
+	desc->AppendL(TPtrC8(&aValue, 1));
+	++iTotalLength;
+	}
+
+/**
+  Encodes input and adds it to the encoded field. Encodes parameter value using WSP 
+  LongInt method.
+ 					
+  @param 			aValue	value to be encoded.
+  @pre				StartHeaderL needs to have been called.
+  @leave			KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::AddLongIntL(const TUint32 aValue)
+	{
+	const TInt arrayCount=iArray.Count();
+	__ASSERT_DEBUG(arrayCount>0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderLNotCalled));
+	CDesC8Array* desc=iArray[arrayCount-1];
+
+	HBufC8* buf = TWspPrimitiveEncoder::LongIntL(aValue);
+	CleanupStack::PushL(buf);
+
+	desc->AppendL(*buf);
+	iTotalLength+=buf->Length();
+
+	CleanupStack::PopAndDestroy(buf);
+	}
+	
+/**
+  Encodes input and adds it to the encoded field. Encodes parameter value using WSP 
+  UIntVar method.
+ 					
+  @param 		aInt	value to be encoded.
+  @pre			StartHeaderL needs to have been called.
+  @leave		KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::AddUintVarL(const TUint aInt)
+	{
+	const TInt arrayCount=iArray.Count();
+	__ASSERT_DEBUG(arrayCount>0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderLNotCalled));
+	CDesC8Array* desc=iArray[arrayCount-1];
+
+	HBufC8*	buf = TWspPrimitiveEncoder::UintVarL(aInt);
+	CleanupStack::PushL(buf);
+
+	desc->AppendL(*buf);
+	iTotalLength+=buf->Length();
+
+	CleanupStack::PopAndDestroy(buf);
+	}
+
+/**
+  Encodes input and adds it to the encoded field. Encodes parameter value using WSP
+  TextString method.
+ 				   
+  @param 			aText		value to be encoded.
+  @pre				StartHeaderL needs to have been called.
+  @leave			KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::AddTextStringL(const TDesC8& aText)
+	{	
+	const TInt arrayCount=iArray.Count();
+	__ASSERT_DEBUG(arrayCount>0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderLNotCalled));
+	CDesC8Array* desc=iArray[arrayCount-1];
+
+	HBufC8*	buf = TWspPrimitiveEncoder::TextStringL(aText);
+	CleanupStack::PushL(buf);
+	desc->AppendL(*buf);
+	iTotalLength+=buf->Length();
+	CleanupStack::PopAndDestroy(buf);
+	}
+
+/**
+  Encodes input and adds it to the encoded field. Encodes parameter value using WSP
+  TextString method.
+  	   	
+  @param 			aText		value to be encoded.
+  @pre				StartHeaderL needs to have been called.
+  @leave			KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::AddTextStringL(const RString& /* aText */)
+	{
+	User::Leave(KErrNotSupported);
+	}
+	
+/**
+  Encodes input and adds it to the encoded field.Encodes parameter value using WSP 
+  Date method.
+ 				   
+  @param 			aDate		value to be encoded.
+  @pre				StartHeaderL needs to have been called.
+  @leave			KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::AddDateL(const TDateTime aDate)
+	{
+	const TInt arrayCount=iArray.Count();
+	__ASSERT_DEBUG(arrayCount>0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderLNotCalled));
+	CDesC8Array* desc=iArray[arrayCount-1];
+
+	HBufC8* buf = TWspPrimitiveEncoder::DateL(aDate);
+	CleanupStack::PushL(buf);
+	desc->AppendL(*buf);
+	iTotalLength+=buf->Length();
+	CleanupStack::PopAndDestroy(buf);
+	}
+	
+/**
+  Encodes input and adds it to the encoded field. Adds value as-is to the encoded field.
+ 				   
+  @param 	aToken	parameter added without encodeing. Should be a valid WSP token, 
+  a 8 bit number > 0x7F (i.e. top bit set).
+  @pre 		StartHeaderL and StartValueLengthL should have been called.
+  @post		EndValueLengthL needs to be called subsequently.
+*/
+EXPORT_C void CWspHeaderEncoder::AddTokenL(const TUint8 aToken)
+	{
+	const TInt arrayCount=iArray.Count();
+	__ASSERT_DEBUG(arrayCount>0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderLNotCalled));
+	CDesC8Array* desc=iArray[arrayCount-1];
+
+	TUint8 shortInt = (TUint8) (aToken); 
+	desc->AppendL(TPtrC8(&shortInt, 1));
+	++iTotalLength;
+	}
+	
+/**
+  Encodes input and adds it to the encoded field. Encodes parameter value using WSP 
+  TokenText method.
+ 				  
+  @param 		aTokenText	value to be encoded.
+  @leave		KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::AddTokenTextL(const TDesC8& aTokenText)
+	{
+	const TInt arrayCount=iArray.Count();
+	__ASSERT_DEBUG(arrayCount>0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderLNotCalled));
+
+	// Step through token text passed in and ensure there are no invalid characters
+	const TInt tokenTextLength = aTokenText.Length();
+	for( TInt ii = 0; ii<tokenTextLength; ++ii)
+		{
+		TUint8 currentChar = aTokenText[ii];
+		if( KTxtSeparators().Locate(currentChar) != KErrNotFound )
+			User::Leave(KErrCorrupt);
+		}
+	// Token text does not contain any invalid characters
+	HBufC8* buf = TWspPrimitiveEncoder::TextStringL(aTokenText);
+	CleanupStack::PushL(buf);
+	CDesC8Array* desc=iArray[arrayCount-1];
+	desc->AppendL(*buf);
+	iTotalLength += buf->Length();
+	CleanupStack::PopAndDestroy(buf);
+	}
+
+/**
+  Encodes input and adds it to the encoded field. Adds value as-is to the encoded field.
+ 					
+  @param 			aData		value to be encoded.
+  @leave			KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::AddDataL(const TDesC8& aData)
+	{
+	const TInt arrayCount=iArray.Count();
+	__ASSERT_DEBUG(arrayCount>0,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartHeaderLNotCalled));
+	CDesC8Array* desc=iArray[arrayCount-1];
+	desc->AppendL(aData);
+	iTotalLength += aData.Length();
+	}
+
+/**
+  From calling this function, the length in bytes of all encodings added subsequently will
+  be calculated and stored as part of the encoded string, as specified in WSP spec.Can be nested. i.e.
+  @code
+	 encoder->StartHeaderL();
+	 encoder->StartValueLengthL();
+	 encoder->StartValueLengthL();
+	 encoder->AddLongIntL();
+	 encoder->EndValueLengthL();
+	 encoder->AddTextStringL();
+	 encoder->EndValueLengthL();
+	 HBufC8* output = encoder->EndHeaderL();
+  @endcode
+ 	
+  @pre 			StartHeaderL should have been called.
+  @post			EndValueLengthL needs to be called subsequently.
+  @leave		KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::StartValueLengthL()
+	{
+	// Create new buffer;
+	CDesC8Array* buffer = new (ELeave) CDesC8ArrayFlat(KDesArrayGranularity);
+	CleanupStack::PushL(buffer);
+	User::LeaveIfError(iArray.Append(buffer));
+	CleanupStack::Pop(buffer);
+	}
+
+/**
+  Needs to be called at the point in the construction of a header when ValueLength 
+  can be calculated.
+ 					  
+  @pre 			StartHeaderL and StartValueLengthL should have been called.
+  @post			ValueLength has been calculated and added, together with the
+ 				encoded header, to the internal representation of the header buffer.
+  @leave		KErrNoMemory
+*/
+EXPORT_C void CWspHeaderEncoder::EndValueLengthL()
+	{
+	const TInt arrayCount=iArray.Count();
+	__ASSERT_ALWAYS(arrayCount>1,User::Panic(KWspCodecPanicCategory, EWspCodecPanicStartValueLengthNotCalled));
+
+	// Calculate the length of the current buffer.
+	// and append it onto the previous buffer. [length value, then data]
+	TUint32 valueLength=0;
+
+
+	CDesC8Array* desc=iArray[arrayCount-1]; // current descriptor being dealt with
+	CDesC8Array* parentDesc=iArray[arrayCount-2]; // parent descriptor to which it must be added.
+
+	TInt buffersToAdd=desc->Count();
+	TInt ii=buffersToAdd;
+
+	// Check the length of all parameters (not the first element in tha array, the field name)
+	while (ii)
+		valueLength+=(*desc)[--ii].Length();
+	
+	// Remove desc from array. Will have to delete also.
+	iArray.Remove(arrayCount-1);
+	CleanupStack::PushL(desc);
+
+	// Depending of size of the length save as number or UintVar
+	if (valueLength < KUintVarIndicator)
+		{
+		// Value length represented by an 8 bit number.
+		AddShortLengthL( (TUint8) valueLength);
+		}
+	else
+		{
+		// Value length represented by an 8bit value indicating a UIntVar follows,
+		// followed by a UIntVar
+		AddShortLengthL( (TUint8) KUintVarIndicator);
+		AddUintVarL(valueLength);
+		}
+
+	// Add field value, parameters etc.
+	ii=0;
+	while (ii<buffersToAdd)
+		parentDesc->AppendL((*desc)[ii++]);
+
+	CleanupStack::PopAndDestroy(desc);
+	}
+
+
+
+
+//**********************************************************************************
+
+/**
+  Takes a TUint8 parameter, and sets the top bit. As specified for the WSP ShortInt 
+  encoding method.
+ 					
+  @param 		aValue number to be encoded.
+  @return 		Output, encoded as a TUint8, representation of the header buffer.
+ 				If input greater that 127 (invalid input), returns 0
+*/
+EXPORT_C TUint8 TWspPrimitiveEncoder::ShortInt(const TUint8 aValue)
+	{
+	// ShortInt should be a character 127 or less. With highest bit set to 1.
+	return (aValue > KWSPQuoteCharacter) ? (TUint8) 0: (TUint8) (aValue | KTopBitMask); 
+	}
+
+/**
+  Takes a TUint32 parameter and encodes it using the WSP specified LongInt method.
+  	
+  @param 			aValue number to be encoded.
+  @return 			Output, encoded HBufC8 buffer. 
+  @leave			KErrNoMemory
+*/
+EXPORT_C HBufC8* TWspPrimitiveEncoder::LongIntL(const TUint32 aValue)
+	{
+	// Consists of size and up to number of 30 bytes.
+	// for a TInt32 the maximum is 4 bytes long.
+	// Check size of number, to determine number of bytes needed to store it.
+
+	TUint8 size = 0; // maximum value is 4 with a 32bit integer
+	TUint32 value=aValue;
+	do {
+		++size;
+		value >>=KLongIntOctetShift; ; // shift by 8 bits.
+		} while (value>0);
+
+	HBufC8* output = HBufC8::NewL(size+1);
+	TPtr8 outPtr(output->Des());
+
+	outPtr.Append(size);
+	TInt ii = size;
+	while (ii-- >0) 
+		{		
+		outPtr.Append( (TUint8) (aValue>>ii*KLongIntOctetShift) );
+		}
+
+	return output;
+	}
+
+/**
+  Takes a TUint32 parameter and encodes it using the WSP specified UintVar method.
+  					
+  @param 			aInt number to be encoded.
+  @return 			Output, encoded HBufC8 buffer. 
+  @leave			KErrNoMemory
+*/
+EXPORT_C HBufC8* TWspPrimitiveEncoder::UintVarL(const TUint32 aInt)
+	{
+	TUint8 size = 0; // maximum value is 5 with a 32bit integer
+	TUint32 value=aInt;
+	do {
+		++size;
+		value >>=KUIntVarOctetShift; ; // shift by 7 bits.
+		} while (value>0);
+
+	HBufC8* output = HBufC8::NewL(size);
+	TPtr8 outPtr(output->Des());
+
+	TInt ii = size; 
+	while (--ii > 0)
+		{
+		outPtr.Append( (TUint8)(aInt>>(KUIntVarOctetShift*(ii))  & KWSPQuoteCharacter) | KCarryBitMask); 
+		} 
+
+	// Finally the first 7 bits, last octet, do not set first bit.
+	outPtr.Append( (TUint8)(aInt & KWSPQuoteCharacter) ); // Add even if 0 value.
+
+	return output;
+	}
+
+/**
+  Takes a RString parameter and encodes it using the WSP specified TextString method.
+  					
+  @param 			aText string to be encoded.
+  @return 			Output, encoded HBufC8 buffer. 
+  @leave			KErrNoMemory
+*/
+EXPORT_C HBufC8* TWspPrimitiveEncoder::TextStringL(const RString  /* aText*/ )
+	{
+	User::Leave(KErrNotSupported);
+	return NULL;
+	}
+
+/**
+  Takes a TDesC8 parameter and encodes it using the WSP specified TextString method.
+  					
+  @param 			aText string to be encoded.
+  @return 			Output, encoded HBufC8 buffer. 
+  @leave			KErrNoMemory
+*/
+EXPORT_C HBufC8* TWspPrimitiveEncoder::TextStringL(const TDesC8& aText)
+	{
+	HBufC8* output=NULL;
+	TInt stringLength = aText.Length();
+	TUint8 firstChar = 0;
+	TUint8 lastChar = 0;
+	if(stringLength>0)
+		{
+		firstChar = aText[0];
+		lastChar = aText[stringLength-1];
+		}
+
+	TPtr8 outPtr(NULL,0);
+	if (firstChar > KWSPQuoteCharacter)
+		{
+		// Apply WSP rule: first character of the string not 7bit add QuoteCharacter.
+		// Add the quote character and include space for the NULL character
+		stringLength+=2;
+		output =  HBufC8::NewL(stringLength); 
+		outPtr.Set(output->Des());
+
+		outPtr.Append(KWSPQuoteCharacter);
+		outPtr.Append(aText);
+		}
+	else if (firstChar==KWSPQuote && lastChar==KWSPQuote)
+		{
+		// Apply WSP rule: if quoted string, remove the closing quote
+		output =  HBufC8::NewL(stringLength); 
+		outPtr.Set(output->Des());
+		outPtr.Append(aText);
+		outPtr.SetLength(stringLength-1);
+		}
+	else
+		{
+		stringLength+=1; // terminating NULL char
+		output =  HBufC8::NewL(stringLength); 
+		outPtr.Set(output->Des());
+		outPtr.Append(aText);
+		}
+
+	// Terminate string with 0x00
+	outPtr.Append(KWspStringTerminator);
+	return output;
+	}
+
+/**
+  Takes a TDateTime parameter and encodes it using the WSP specified Date encoding method.
+  
+  @param 			aDate value to be encoded.
+  @return 			Output, encoded HBufC8 buffer. 
+  @leave			KErrNoMemory
+*/
+EXPORT_C HBufC8* TWspPrimitiveEncoder::DateL(const TDateTime aDate)
+	{
+	TTime baseTime(TDateTime(1970,EJanuary,0,0,0,0,0));
+	TTime dateTime(aDate);
+	TTimeIntervalSeconds interval;
+	dateTime.SecondsFrom(baseTime, interval);
+
+	return LongIntL(interval.Int());
+	}
+