sl@0: // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: //
sl@0: 
sl@0: // System includes
sl@0: #include <uri8.h>
sl@0: #include <uri16.h>
sl@0: #include <uriutils.h>
sl@0: #include <uriutilscommon.h>
sl@0: 
sl@0: 
sl@0: //User includes
sl@0: #include "TUriParserInternal.h"
sl@0: #include "UriUtilsInternal.h"
sl@0: #include "TUriCInternal.h"
sl@0: #include "GenericUriParser.h"
sl@0: #include "SipUriParser.h"
sl@0: 
sl@0: 
sl@0: 
sl@0: // Constants
sl@0: //
sl@0: 
sl@0: _LIT8(KSIP, "Sip");
sl@0: _LIT8(KSIPS, "Sips");
sl@0: 
sl@0: 
sl@0: //
sl@0: //
sl@0: // Implementation of TUriParser8
sl@0: //
sl@0: //
sl@0: 
sl@0: /**
sl@0: 	Constructor.
sl@0: 	
sl@0: 	@since			6.0
sl@0:  */
sl@0: EXPORT_C TUriParser8::TUriParser8()
sl@0: : TUriC8()
sl@0: 	{
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: 	Parses the descriptor aUri into uri components.
sl@0: 	
sl@0: 	@since			6.0
sl@0: 	@param			aUri A reference to a descriptor pointer to be parsed.
sl@0: 	@return			KErrNone if the descriptor has been parsed into uri components.
sl@0: 	KUriUtilsParserErrInvalidUri if the descriptor is an invalid uri.
sl@0: 	KErrNoMemory if out of memory
sl@0: 	@post			The object references the input descriptor.
sl@0:  */
sl@0: EXPORT_C TInt TUriParser8::Parse(const TDesC8& aUri)
sl@0: 	{
sl@0: 	// Reset the Uri information and then set the Uri
sl@0: 	if( iUriDes.Length() )
sl@0: 		{
sl@0: 		Reset();
sl@0: 		}
sl@0: 	iUriDes.Set(aUri);
sl@0: 
sl@0: 	// Check uri is valid
sl@0: 	if( iUriDes.Length() && iUriDes[0]==KSchemeDelimiter )
sl@0: 		{
sl@0: 		return KUriUtilsErrInvalidUri;
sl@0: 		}
sl@0: 	
sl@0: 	TPtrC8 schemeComponent;
sl@0: 	RetrieveScheme(iUriDes,schemeComponent);
sl@0: 	CGenericUriParser* UriHandler = NULL;
sl@0: 	TInt err=KErrNone;
sl@0: 	if(schemeComponent.CompareF(KSIP()) == 0 || schemeComponent.CompareF(KSIPS()) == 0 )
sl@0: 		{
sl@0: 	    TRAP(err,UriHandler = CSIPUriParser::NewL());
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 	    TRAP(err,UriHandler = CGenericUriParser::NewL());
sl@0:  		}
sl@0: 	if(UriHandler)
sl@0: 		{
sl@0: 		UriHandler->DoParseUri(iUriDes, iComponent);
sl@0: 		delete UriHandler;
sl@0: 		}
sl@0:        
sl@0: 		return err;      
sl@0: 
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: 	Parses the descriptor aUri into uri components.
sl@0: 	
sl@0: 	@param			aUri A reference to a descriptor pointer of an Uri.
sl@0: 	@param			aScheme A reference to a descriptor pointer for retieved 
sl@0: 					scheme component.
sl@0:  */
sl@0: void TUriParser8::RetrieveScheme(const TPtrC8& aUri, TPtrC8& aScheme)
sl@0: 	{
sl@0: 	TInt schemePos = aUri.Locate(KSchemeDelimiter);
sl@0: 	if(schemePos != KErrNotFound)
sl@0: 		{
sl@0: 		// Got a scheme - store information
sl@0: 		aScheme.Set(aUri.Left(schemePos));
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: //
sl@0: //
sl@0: // Implementation of TUriParser16
sl@0: //
sl@0: //
sl@0: 
sl@0: /**
sl@0: 	Constructor.
sl@0: 	
sl@0: 	@since			6.0
sl@0: 	@deprecated Deprecated in 9.1
sl@0:  */
sl@0: EXPORT_C TUriParser16::TUriParser16()
sl@0: : TUriC16()
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: 	Parses the descriptor aUri into uri components.
sl@0: 	
sl@0: 	@since			6.0
sl@0: 	@deprecated Deprecated in 9.1
sl@0: 	@param			aUri A reference to a descriptor pointer to be parsed.
sl@0: 	@return			KErrNone if the descriptor has been parsed into uri components.
sl@0: 	EUriParserErrInvalidUri if the descriptor is an invalid uri.
sl@0: 	@post			The object references the input descriptor.
sl@0:  */
sl@0: EXPORT_C TInt TUriParser16::Parse(const TDesC16& aUri)
sl@0: 	{
sl@0: 	// Reset the Uri information and then set the Uri
sl@0: 	if( iUriDes.Length() )
sl@0: 		Reset();
sl@0: 	iUriDes.Set(aUri);
sl@0: 
sl@0: 	// Check uri is valid
sl@0: 	if( iUriDes.Length() && iUriDes[0]==KSchemeDelimiter )
sl@0: 		return KUriUtilsErrInvalidUri;
sl@0: 
sl@0: 	// Parse the uri.
sl@0: 	DoParseUri(iUriDes, iComponent);
sl@0: 	return KErrNone;
sl@0: 	}
sl@0: 
sl@0: //
sl@0: //
sl@0: // Implementation of templated LOCAL functions
sl@0: //
sl@0: //
sl@0: 
sl@0: /**
sl@0: 	Templated function that parses a descriptor into the components of a uri.
sl@0: 						
sl@0: 	@since			6.0
sl@0: 	@param			aUri		The descriptor with the data to parse.
sl@0: 	@param			aComponent	The output array of descriptors of each uri component.
sl@0: 	@pre 			Each descriptor pointer in aComponent has had the pointer to its
sl@0: 					associated descriptor buffer set to NULL.
sl@0: 	@post			The descriptor pointers in aComponent are updated to refer to the 
sl@0: 					appropriate sections of aUri that represent the components of a uri.
sl@0: */
sl@0: template<class TPtrCType>
sl@0: void DoParseUri(const TPtrCType& aUri, TPtrCType aComponent[])
sl@0: 	{
sl@0: 	// Parse the components
sl@0: 	TPtrCType uri = aUri;
sl@0: 	TInt consumed = 0;
sl@0: 	TPtrCType& scheme = aComponent[EUriScheme];
sl@0: 	if( (consumed = ParseScheme(uri, scheme)) > 0 )
sl@0: 		{
sl@0: 		uri.Set(uri.Mid(consumed));
sl@0: 		}
sl@0: 	if( (consumed = ParseAuthority(uri, aComponent[EUriUserinfo], 
sl@0: 		 aComponent[EUriHost], aComponent[EUriPort], IsNetworkScheme(scheme))) > 0 )
sl@0: 		{
sl@0: 		uri.Set(uri.Mid(consumed));
sl@0: 		}
sl@0: 	if( (consumed = ParsePath(uri, aComponent[EUriPath])) > 0 )
sl@0: 		{
sl@0: 		uri.Set(uri.Mid(consumed));
sl@0: 		}
sl@0: 	if( (consumed = ParseQuery(uri, aComponent[EUriQuery])) > 0 )
sl@0: 		{
sl@0: 		uri.Set(uri.Mid(consumed));
sl@0: 		}
sl@0: 	if( (consumed = ParseFragment(uri, aComponent[EUriFragment])) > 0 )
sl@0: 		{
sl@0: 		uri.Set(uri.Mid(consumed));
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: 	Templated function to parse a descriptor for a scheme component. If a scheme is found 
sl@0: 	then the output argument aScheme is set to refer to it.
sl@0: 						
sl@0: 	@since			6.0
sl@0: 	@param			aUri	The descriptor containing the uri to be parsed for 
sl@0: 	a scheme.
sl@0: 	@param			aScheme	The output descriptor to refer to the scheme
sl@0: 	@return			The number of characters consumed in parsing the scheme.
sl@0: 	@pre 			The output descriptor has been initialized so that the pointer
sl@0: 					to the associated descriptor buffer is NULL. The input descriptor 
sl@0: 					is set to the start of the uri.
sl@0: 	@post			If a scheme component exists then the output descriptor refers
sl@0: 					to it, otherwise the output descriptor is left unchanged.
sl@0: */
sl@0: template<class TPtrCType>
sl@0: TInt ParseScheme(const TPtrCType& aUri, TPtrCType& aScheme)
sl@0: 	{
sl@0: 	// Get the descriptor and look for scheme delimiter
sl@0: 	TInt consumed =0;
sl@0: 	TInt endSchemePos = FindFirstUriDelimiter(aUri, ESchemeDelimiterSearch);
sl@0: 
sl@0: 	if( endSchemePos != KErrNotFound )
sl@0: 		{
sl@0: 		// Got a scheme - store information
sl@0: 		aScheme.Set(aUri.Left(endSchemePos));
sl@0: 
sl@0: 		// Set consumed amount move past scheme delimiter
sl@0: 		consumed = endSchemePos + 1;
sl@0: 		}
sl@0: 	return consumed;
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: 	Templated function to parse a descriptor for an authority component. If an authority is 
sl@0: 	found then the output arguments aUserinfo, aHost and aPort are set to refer to those parts 
sl@0: 	of the authority component. If an authority component exists then the host part exists. The 
sl@0: 	userinfo and port parts are optional.
sl@0: 						
sl@0: 	@since			6.0
sl@0: 	@param			aUri		The descriptor containing the uri to be parsed 
sl@0: 					for an authority.
sl@0: 	@param			aUserinfo	The output descriptor for the userinfo component.
sl@0: 	@param			aHost		The output descriptor for the host component.
sl@0: 	@param			aPort		The output descriptor for the port component.
sl@0: 	@param			aUseNetworkDelimiter Whether the scheme uses the network delimeter '//'
sl@0: 	@return			The number of characters consumed in parsing the authority.
sl@0: 	@pre 			The output descriptors have been initialized so that the pointer
sl@0: 					to the their associated descriptor buffers is NULL. The input descriptor 
sl@0: 					is set to the start of the start of the authority component.
sl@0: 	
sl@0: 	@post			If an authority component exists then the output descriptors refer
sl@0: 					to the userinfo part (if exists), the host part and the port part (if exists), 
sl@0: 					otherwise the output descriptors are left unchanged.
sl@0: */
sl@0: 
sl@0: template<class TPtrCType> 
sl@0: TInt ParseAuthority(const TPtrCType& aUri, TPtrCType& aUserinfo, TPtrCType& aHost, TPtrCType& aPort, TBool aUseNetworkDelimiter)
sl@0: 	{
sl@0: 	// Get uri descriptor and see if authority exists - if aUseNetworkDelimiter is true it has to start with '//' 
sl@0: 	TInt consumed =0;
sl@0: 	const TInt prefixLength = aUseNetworkDelimiter ? KUriNetworkAuthorityDelimiterLength : 0;
sl@0:   	if( !aUseNetworkDelimiter || 
sl@0:   		(aUri.Length() >= prefixLength && aUri[0] == KSlashDelimiter && aUri[1] == KSlashDelimiter ))
sl@0: 		{
sl@0: 		// There is an authority
sl@0: 		TPtrCType authority = aUri.Mid(prefixLength);
sl@0: 
sl@0: 		// Authority delimited by '/', '?', '#' or the end of the string
sl@0: 		TInt authorityEndPos = FindFirstUriDelimiter(authority, EAuthDelimiterSearch);
sl@0: 
sl@0: 		// Got authority - parse it for its components
sl@0: 		authority.Set(authority.Left(authorityEndPos));
sl@0: 
sl@0: 		// Get the userinfo...
sl@0: 		TInt userinfoEndPos = authority.Locate(KUserinfoDelimiter);
sl@0: 		if( userinfoEndPos != KErrNotFound )
sl@0: 			{
sl@0: 			// Store the information 
sl@0: 			aUserinfo.Set(authority.Left(userinfoEndPos));
sl@0: 			  
sl@0: 			// Move past the userinfo and the delimiter '@'
sl@0: 			authority.Set(authority.Mid(userinfoEndPos + 1));
sl@0: 			}
sl@0: 
sl@0: 		// Authority is also delimited by ';' but this is valid in the userinfo so can only be checked now
sl@0: 		TInt semicolonPos = FindFirstUriDelimiter(authority, ESemiColonDelimiterFlag);
sl@0: 		if ( semicolonPos != KErrNotFound )
sl@0: 			{
sl@0: 			authority.Set(authority.Left(semicolonPos));
sl@0: 			authorityEndPos = semicolonPos + userinfoEndPos + 1;
sl@0: 			}
sl@0: 		
sl@0: 		// Set consumed amount to move past authority
sl@0: 		consumed += prefixLength + authorityEndPos;
sl@0: 		
sl@0: 		// Check if this is an IPv6 address	by looking for the opening '['
sl@0: 		TInt startHostIPv6 = authority.Locate(KIPv6UriOpenBrace);
sl@0: 
sl@0: 		if (startHostIPv6==KErrNotFound)
sl@0: 			{
sl@0: 			// This isn't an IPv6 address.....
sl@0: 
sl@0: 			// Get host...
sl@0: 			TInt hostEndPos = authority.Locate(KPortDelimiter);
sl@0: 
sl@0: 			// Host also delimited by the end of the authority
sl@0: 			if( hostEndPos == KErrNotFound )
sl@0: 				hostEndPos = authority.Length();
sl@0: 
sl@0: 			// There's always a host, but can be empty - store information
sl@0: 			aHost.Set(authority.Left(hostEndPos));
sl@0: 
sl@0: 			// Move past the host
sl@0: 			authority.Set(authority.Mid(hostEndPos));
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 		
sl@0: 	    // First, move past the opening brace
sl@0: 	        authority.Set(authority.Mid(startHostIPv6 + 1));
sl@0: 	            // auth now = X:X:X]?????
sl@0: 	            
sl@0: 			// This is an IPv6 address, so it MUST have the closing brace too....
sl@0: 			TInt endIPv6Host = authority.Locate(KIPv6UriCloseBrace);
sl@0: 
sl@0: 			// Return an error if the closing IPv6 delimiter isn't there.
sl@0: 			if (endIPv6Host==KErrNotFound)
sl@0: 				return KUriUtilsErrInvalidUri;
sl@0: 
sl@0: 			// It's an ipv6  address, with an opening and closing brace. So now just extract it
sl@0: 			// auth = [X:X:X]?????
sl@0: 
sl@0: 
sl@0: 			// Set the host, and need to remove the closing brace
sl@0: 			aHost.Set(authority.Left(endIPv6Host));
sl@0: 			// host = X:X:X
sl@0: 
sl@0: 			// Move past the host
sl@0: 			authority.Set(authority.Mid(endIPv6Host + 1 ));
sl@0: 			}
sl@0: 		
sl@0: 		// Get the port...
sl@0: 		TInt portEndPos = authority.Length();
sl@0: 		if( portEndPos )
sl@0: 			{
sl@0: 			// Store the port - remove leading ':'
sl@0: 			aPort.Set(authority.Mid(1, portEndPos - 1));
sl@0: 			}
sl@0: 		}
sl@0: 	return consumed;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: 	Templated function to parse a descriptor for a path component.There is always a path component.
sl@0: 	The ouput argument aPath is set to the path component found.
sl@0: 						
sl@0: 	@since			6.0
sl@0: 	@param			aUri	The descriptor containing the uri to be parsed for 
sl@0: 	a path.
sl@0: 	@param			aComponent	The output descriptor to refer to the path.
sl@0: 	@return			The number of characters consumed in parsing the path.
sl@0: 	@pre 			The output descriptor has been initialized so that the pointer
sl@0: 					to the associated descriptor buffer is NULL. The input descriptor 
sl@0: 					is set to the start of the path.
sl@0: 					
sl@0: 	@post			The output descriptor refers to the path component.
sl@0: */
sl@0: template<class TPtrCType>
sl@0: TInt ParsePath(const TPtrCType& aUri, TPtrCType& aComponent)
sl@0: 	{
sl@0: 	// Get descriptor with the path
sl@0: 	TInt consumed =0;
sl@0: 
sl@0: 	// Path is delimited by '?'. '#' or the end of the string
sl@0: 	TInt pathEndPos = FindFirstUriDelimiter(aUri, EPathDelimiterSearch);
sl@0: 
sl@0: 	// Check for presence of path
sl@0: 	if( pathEndPos != KErrNotFound )
sl@0: 		{
sl@0: 		// Got path - store information
sl@0: 		aComponent.Set(aUri.Left(pathEndPos));
sl@0: 	
sl@0: 		// Set consumed amount to move past path
sl@0: 		consumed = pathEndPos;
sl@0: 		}
sl@0: 	return consumed;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: 	Templated function to parse a descriptor for a query component.If a query is found then 
sl@0: 	the output argument aQuery is set to refer to it.
sl@0: 						
sl@0: 	@since			6.0
sl@0: 	@param			aUri	The descriptor containing the uri to be parsed for 
sl@0: 	a query.
sl@0: 	@param			aComponent	The output descriptor to refer to the query
sl@0: 	@return			The number of characters consumed in parsing the query.
sl@0: 	@pre 			The output descriptor has been initialized so that the pointer
sl@0: 					to the associated descriptor buffer is NULL. The input descriptor is set to
sl@0: 					the start of the query.
sl@0: 	@post			If a query component exists then the output descriptor refers
sl@0: 					to it, otherwise the output descriptor is left unchanged.
sl@0: */
sl@0: template<class TPtrCType>
sl@0: TInt ParseQuery(const TPtrCType& aUri, TPtrCType& aComponent)
sl@0: 	{
sl@0: 	// Get descriptor with the query
sl@0: 	TInt consumed =0;
sl@0: 
sl@0: 	// Query is delimited by '#' or end of the string 
sl@0: 	TInt queryEndPos = FindFirstUriDelimiter(aUri, EQueryDelimiterSearch);
sl@0: 
sl@0: 	// Check for presence of query
sl@0: 	if( queryEndPos )
sl@0: 		{
sl@0: 		// Got query - store information; need to excluded leading '?'
sl@0: 		aComponent.Set(aUri.Mid(1, queryEndPos - 1));
sl@0: 	
sl@0: 		// Set consumed amount to move past query
sl@0: 		consumed = queryEndPos;
sl@0: 		}
sl@0: 	return consumed;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: 	Templated function to parse a descriptor for a fragment component. If a fragment is found then 
sl@0: 	the output argument aFragment is set to refer to it.
sl@0: 						
sl@0: 	@since			6.0
sl@0: 	@param			aUri		The descriptor containing the uri to be parsed for 
sl@0: 					a fragment.
sl@0: 	@param			aComponent	The output descriptor to refer to the fragment.
sl@0: 	@return			The number of characters consumed in parsing the fragment.
sl@0: 	@pre 			The output descriptor has been initialized so that the pointer
sl@0: 					to the associated descriptor buffer is NULL. The input descriptor is set to
sl@0: 					the start of the fragment.
sl@0: 	@post			If a fragment component exists then the output descriptor refers
sl@0: 					to it, otherwise the output descriptor is left unchanged.
sl@0: */
sl@0: template<class TPtrCType>
sl@0: TInt ParseFragment(const TPtrCType& aUri, TPtrCType& aComponent)
sl@0: 	{
sl@0: 	// Get descriptor with the fragment
sl@0: 	TInt consumed =0;
sl@0: 
sl@0: 	// Fragment is delimited by end of the string
sl@0: 	TInt fragmentEndPos = aUri.Length();
sl@0: 
sl@0: 	// Check for presence of fragment
sl@0: 	if( fragmentEndPos )
sl@0: 		{
sl@0: 		// Got fragment - store information; need to excluded leading '#'
sl@0: 		aComponent.Set(aUri.Mid(1, fragmentEndPos - 1));
sl@0: 	
sl@0: 		// Set consumed amount to move past fragment
sl@0: 		consumed = fragmentEndPos;
sl@0: 		}
sl@0: 	return consumed;
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: 	Templated function to find the position of the first delimiter in the descriptor specified 
sl@0: 	by the delimiter flags. Note that the end of the descriptor is also a delimiter if there are 
sl@0: 	no others. In the case of the scheme delimiter search, the position returned depends on the 
sl@0: 	position of the colon delimiter with respect to the other delimiters for a scheme.
sl@0: 						
sl@0: 	@since			6.0
sl@0: 	@param			aUri		The descriptor containing the section of a uri to be searched.
sl@0: 	@param			aSearchFlag	The enum specifying the delimiters to search for.
sl@0: 	@return			The position of nearest delimiter to start of the descriptor, where
sl@0: 					zero is the start (left-most) position.
sl@0: */
sl@0: template<class TPtrCType> 
sl@0: TInt FindFirstUriDelimiter(const TPtrCType& aUri, TDelimiterSearchFlag aSearchFlag)
sl@0: 	{
sl@0: 	// Set ultimate delimiter - string length
sl@0: 	TInt endPos = aUri.Length();
sl@0: 	if( aSearchFlag & EHashDelimiterFlag )
sl@0: 		{
sl@0: 		TInt fragmentPos = aUri.Locate(KFragmentDelimiter);
sl@0: 		if( fragmentPos != KErrNotFound && fragmentPos < endPos )
sl@0: 			endPos = fragmentPos;
sl@0: 		}
sl@0: 	if( aSearchFlag & EQueryDelimiterFlag )
sl@0: 		{
sl@0: 		TInt queryPos = aUri.Locate(KQueryDelimiter);
sl@0: 		if( queryPos != KErrNotFound && queryPos < endPos )
sl@0: 			endPos = queryPos;
sl@0: 		}
sl@0: 	if( aSearchFlag & ESlashDelimiterFlag )
sl@0: 		{
sl@0: 		TInt slashPos = aUri.Locate(KSlashDelimiter);
sl@0: 		if( slashPos != KErrNotFound && slashPos < endPos )
sl@0: 			endPos = slashPos;
sl@0: 		}
sl@0: 	if( aSearchFlag & ESemiColonDelimiterFlag )
sl@0: 		{
sl@0: 		TInt semiColonPos = aUri.Locate(KParamDelimiter);
sl@0: 		if( semiColonPos != KErrNotFound && semiColonPos < endPos )
sl@0: 			endPos = semiColonPos;
sl@0: 		}
sl@0: 	if( aSearchFlag & EColonDelimiterFlag )
sl@0: 		{
sl@0: 		TInt schemePos = aUri.Locate(KSchemeDelimiter);
sl@0: 		if( schemePos != KErrNotFound && schemePos < endPos )
sl@0: 			{
sl@0: 			// There is a scheme
sl@0: 			endPos = schemePos;
sl@0: 			}
sl@0: 		else if( aSearchFlag == ESchemeDelimiterSearch )
sl@0: 			{
sl@0: 			// Ok different if looking for scheme delimiter - no scheme, return KErrNotFound
sl@0: 			endPos = KErrNotFound;
sl@0: 			}
sl@0: 		}
sl@0: 	return endPos;
sl@0: 	}