realtimenetprots/sipfw/SIP/Codec/src/CSIPPreParser.cpp
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/Codec/src/CSIPPreParser.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,438 @@
+// Copyright (c) 2004-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:
+// Name          : CSIPPreParser.cpp
+// Part of       : SIP Codec
+// Version       : SIP/4.0 
+//
+
+
+
+
+#include "CSIPPreParser.h"
+#include "CSIPHeaderNameValue.h"
+#include "sipcodecerr.h"
+
+_LIT8 (KCRLFCRLF, "\r\n\r\n");
+_LIT8 (KCRCRLF, "\r\r\n");
+_LIT8 (KLFCRLF, "\n\r\n");
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::NewL
+// -----------------------------------------------------------------------------
+//
+CSIPPreParser* CSIPPreParser::NewL (HBufC8* aSipMessageBuf)
+	{
+	CSIPPreParser* self= CSIPPreParser::NewLC (aSipMessageBuf);
+	CleanupStack::Pop(self);
+	return self;
+	} 
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::NewLC
+// -----------------------------------------------------------------------------
+//
+CSIPPreParser* CSIPPreParser::NewLC (HBufC8* aSipMessageBuf)
+	{
+	__ASSERT_ALWAYS (aSipMessageBuf!=0, User::Leave(KErrSipCodecPreParser));
+	__ASSERT_ALWAYS (aSipMessageBuf->Length()>0, User::Leave(KErrSipCodecPreParser));
+
+	CSIPPreParser* self= new(ELeave)CSIPPreParser (*aSipMessageBuf);
+	CleanupStack::PushL(self);
+	self->ConstructL(aSipMessageBuf);
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::CSIPPreParser
+// -----------------------------------------------------------------------------
+//
+CSIPPreParser::CSIPPreParser (const TDesC8& aSipMessageDes)
+ : iLexBuf(aSipMessageDes)
+	{
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CSIPPreParser::ConstructL (HBufC8* aSipMessageBuf)
+	{
+	CreateHeaderBufL (*aSipMessageBuf);
+	ParseL ();
+	// aSipMessageBuf ownership taken only after the pre-parsing has succeeded.
+	iSipMessageBuf = aSipMessageBuf;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::~CSIPPreParser
+// -----------------------------------------------------------------------------
+//
+CSIPPreParser::~CSIPPreParser ()
+	{
+    iHeaderStartArray.Close();
+	delete iHeaderBuf;
+	delete iSipMessageBuf;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::ParseL
+// -----------------------------------------------------------------------------
+//
+void CSIPPreParser::ParseL ()
+	{
+	TChar chr = GetCharL();
+	while (chr == ' ' || chr == '\t' || chr == '\r' || chr == '\n')
+		{
+		chr = GetCharL();
+		}
+
+	TBool headerPartEnds = EFalse;
+	while (!headerPartEnds)
+		{
+		switch (chr)
+			{
+			case '\n': headerPartEnds = HandleLfL(); break;
+			case '\r': headerPartEnds = HandleCrL(); break;
+			default: iHeaderBuf->Des().Append(chr); break;
+			}
+		if (!headerPartEnds)
+		    {
+		    chr = GetChar();
+		    }
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::FirstLineL
+// -----------------------------------------------------------------------------
+//
+TPtrC8 CSIPPreParser::FirstLineL ()
+	{
+	// The first line of any SIP message is a request line or a status line.
+	TPtrC8 firstLine(GetLineL(0));
+	return firstLine;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::ContentL
+// -----------------------------------------------------------------------------
+//
+HBufC8* CSIPPreParser::ContentL ()
+	{
+	// The ownership of the content is given to the caller.
+	// The function is not re-entrant. Content can be only asked once.
+	// The purpose of this is to avoid unnecessary copying.
+	__ASSERT_ALWAYS (iSipMessageBuf != 0, User::Leave (KErrSipCodecPreParser));
+
+	// Delete the header part from the original SIP message. "Delete" does not
+	// free any memory. It just changes the starting position of the descriptor
+	// in the original buffer.
+	TInt originalLength = iSipMessageBuf->Length();
+	iSipMessageBuf->Des().Delete (0, iOriginalHeaderPartLength);
+	TInt contentLength = originalLength - iOriginalHeaderPartLength;
+
+	// With relatively big content parts try to avoid unnecessary copying. 
+	HBufC8* content = NULL;
+	if (contentLength < iOriginalHeaderPartLength)
+		{
+		// Relatively small content part. Make a copy. See HBufC8::ReAllocL.
+		content = iSipMessageBuf->ReAllocL (contentLength);
+		}
+	else
+		{
+		// Relatively big content part. Do not copy into smaller buffer.
+		content = iSipMessageBuf;
+		}
+	iSipMessageBuf = 0;
+	return content;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::HeaderCount
+// -----------------------------------------------------------------------------
+//
+TUint CSIPPreParser::HeaderCount ()
+	{
+	return iHeaderStartArray.Count();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::ParseNameValueL
+// -----------------------------------------------------------------------------
+//
+CSIPHeaderNameValue* CSIPPreParser::ParseNameValueL (TInt aIndex)
+	{
+	__ASSERT_ALWAYS (aIndex < iHeaderStartArray.Count(), 
+					User::Leave(KErrSipCodecPreParser));
+
+	TUint lineStartPos = iHeaderStartArray[aIndex];
+    TPtrC8 line (GetLineL(lineStartPos));
+	TInt colonPos = line.Locate (':'); // find the first colon
+
+	__ASSERT_ALWAYS (colonPos > 0, User::Leave(KErrSipCodecPreParser));
+
+	TPtrC8 name(line.Left(colonPos));
+	TPtrC8 value(line.Mid(colonPos+1));
+
+	return CSIPHeaderNameValue::NewL(name, value);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::GetLineL
+// -----------------------------------------------------------------------------
+//
+TPtrC8 CSIPPreParser::GetLineL (TInt aLineStartPosition)
+	{
+    __ASSERT_ALWAYS (aLineStartPosition < iHeaderBuf->Length(),
+					User::Leave(KErrSipCodecPreParser));
+
+	TPtrC8 lineStartBuf (iHeaderBuf->Des().Mid (aLineStartPosition));
+
+	// All the line ends (CR,LF or CRLF) have been replaced by LF.
+	TInt lineEndPosition = lineStartBuf.Locate('\n');
+	
+    __ASSERT_ALWAYS (lineEndPosition > 0, User::Leave (KErrSipCodecPreParser));
+
+	return lineStartBuf.Left(lineEndPosition);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::CreateHeaderBufL
+// -----------------------------------------------------------------------------
+//
+void CSIPPreParser::CreateHeaderBufL (const TDesC8& aSipMessageDes)
+	{
+	TLex8 lex(aSipMessageDes);
+	lex.SkipSpace();
+    TInt headerPartEndPosition = 0;
+    FindHeaderPartEndPositionL (lex.Remainder(),headerPartEndPosition);
+	if (headerPartEndPosition <= 0) 
+		{
+		User::Leave (KErrSipCodecPreParser);
+		}
+	iHeaderBuf = HBufC8::NewL(headerPartEndPosition+1);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::FindHeaderPartEndPositionL
+// -----------------------------------------------------------------------------
+//
+void CSIPPreParser::FindHeaderPartEndPositionL (
+    const TDesC8& aSipMessageDes,
+    TInt& aPosition)
+	{
+	// The header part may end only with CRLFCRLF, CRCRLF or LFCRLF
+	RArray<TInt> positions;
+	CleanupClosePushL(positions);
+
+	// CRLFCRLF
+	TInt CrLfCrLfPos = aSipMessageDes.Find(KCRLFCRLF);
+    if (CrLfCrLfPos >= 0) 
+        {
+        User::LeaveIfError(positions.Append(CrLfCrLfPos));
+        }
+	
+	// CRCRLF
+	TInt CrCrLfPos = aSipMessageDes.Find(KCRCRLF);
+	if (CrCrLfPos >= 0) 
+        {
+        User::LeaveIfError(positions.InsertInOrder(CrCrLfPos));
+        }
+	
+	// LFCRLF
+	TInt LfCrLfPos = aSipMessageDes.Find(KLFCRLF);
+	if (LfCrLfPos >= 0) 
+        {
+        User::LeaveIfError(positions.InsertInOrder(LfCrLfPos));
+        }
+
+	if (positions.Count() == 0)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	aPosition = positions[0];
+	CleanupStack::PopAndDestroy(); // positions
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::HandleLfL
+// -----------------------------------------------------------------------------
+//
+TBool CSIPPreParser::HandleLfL ()
+	{
+	TChar chr = GetCharL ();
+	switch (chr)
+		{
+		case ' ' : // LFSP 
+		case '\t': // LFHTAB
+			// The header continues on the next line.
+			SkipSpacesAndTabsL ();
+			iHeaderBuf->Des().Append(' '); // replace by one space
+			break;
+
+		case '\r': // LFCR
+			chr = GetCharL ();
+			if (chr == '\n') // LFCRLF
+				{
+				// Header part ends according to the old SIP specs.
+				// Replace LFCRLF with LF to simplify name-value parsing.
+				iHeaderBuf->Des().Append('\n');
+				return ETrue; 
+				}
+			else // LFCR"AnyText" not allowed.
+				{
+				User::Leave (KErrSipCodecPreParser);
+				}
+
+		case '\n': // LFLF not allowed.
+			User::Leave (KErrSipCodecPreParser);
+
+		default: // LF"AnyText"
+			MoveToNextLineL ();
+			break;
+		}
+	return EFalse;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::HandleCrL
+// -----------------------------------------------------------------------------
+//
+TBool CSIPPreParser::HandleCrL ()
+	{
+	TChar chr = GetCharL ();
+	switch (chr)
+		{
+		case ' ' : // CRSP
+		case '\t': // CRHTAB
+			// The header continues on the next line.
+			SkipSpacesAndTabsL ();
+			iHeaderBuf->Des().Append(' '); // replace by one space
+			break;
+
+		case '\r': // CRCR
+			chr = GetCharL ();
+			if (chr == '\n') // CRCRLF
+				{
+				// Header part ends according to the old SIP specs.
+				// Replace CRCRLF with LF to simplify name-value parsing.
+				iHeaderBuf->Des().Append('\n');
+				return ETrue;
+				}
+			else // CRCR"AnyText" not allowed.
+				{
+				User::Leave (KErrSipCodecPreParser); 
+				}
+
+		case '\n': // CRLF
+			chr = GetCharL ();
+			switch (chr)
+				{
+				case '\n': // CRLFLF not allowed.
+					User::Leave (KErrSipCodecPreParser);
+
+				case ' ' : case '\t': // CRLFSP or CRLFHTAB
+					// The header continues on the next line.
+					SkipSpacesAndTabsL ();
+					iHeaderBuf->Des().Append(' '); // replace by one space
+					break;
+
+				case '\r': // CRLFCR
+					chr = GetCharL ();
+					if (chr == '\n') // CRLFCRLF. Header part ends.
+						{
+						// Replace with LF to simplify name-value parsing.
+						iHeaderBuf->Des().Append('\n');
+						return ETrue;
+						}
+					else // CRLFCR"AnyText" not allowed.
+						{
+						User::Leave (KErrSipCodecPreParser); 
+						}
+
+				default: // CRLF"AnyText"
+					MoveToNextLineL ();
+					break;
+				}
+			break;
+	
+		default: // CR"AnyText"
+			MoveToNextLineL ();
+			break;
+		}
+	return EFalse;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::SkipSpacesAndTabsL
+// -----------------------------------------------------------------------------
+//
+void CSIPPreParser::SkipSpacesAndTabsL ()
+	{
+	TChar chr = GetCharL ();
+	while (chr == ' ' || chr == '\t')
+		{
+		chr = GetCharL();
+		}
+	UnGetChar(); // Put back the last one that was not a space or a tab
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::MoveToNextLineL
+// -----------------------------------------------------------------------------
+//
+void CSIPPreParser::MoveToNextLineL ()
+	{
+	UnGetChar();
+	// Replace the line end (CR, LF or CRLF) with LF
+	iHeaderBuf->Des().Append('\n');
+	TUint nextLineStartPosition = iHeaderBuf->Length();
+	User::LeaveIfError (iHeaderStartArray.Append(nextLineStartPosition));
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::GetCharL
+// -----------------------------------------------------------------------------
+//
+inline TChar CSIPPreParser::GetCharL()
+	{
+    TChar chr = GetChar();
+	if (chr == 0) 
+        {
+        User::Leave (KErrSipCodecPreParser);
+        }
+    return chr;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::GetChar
+// -----------------------------------------------------------------------------
+//
+inline TChar CSIPPreParser::GetChar()
+	{
+	TChar chr = iLexBuf.Get();
+	if (chr != 0) iOriginalHeaderPartLength++;
+    return chr;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPPreParser::UnGetChar
+// -----------------------------------------------------------------------------
+//
+inline void CSIPPreParser::UnGetChar()
+	{
+	iLexBuf.UnGet();
+	iOriginalHeaderPartLength--;
+	}