diff -r 000000000000 -r e4d67989cc36 genericservices/httputils/UriUtils/UriUtils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/genericservices/httputils/UriUtils/UriUtils.cpp Tue Feb 02 02:01:42 2010 +0200 @@ -0,0 +1,888 @@ +// 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 +#include +#include "UriUtilsInternal.h" +#include + +_LIT8(KDot, "."); +_LIT8(KDotDot, ".."); +_LIT8(KDotSlash, "./"); +_LIT8(KDotDotSlash, "../"); +_LIT8(KSlash, "/"); +_LIT8(KSlashDot, "/."); +_LIT8(KSlashDotDot, "/.."); +_LIT8(KSlashDotSlash, "/./"); +_LIT8(KSlashDotDotSlash, "/../"); + +_LIT(KHexDigit, "0123456789ABCDEF"); +_LIT(KUnreserved, "-.~_"); +#ifdef _DEBUG +_LIT(KNormalisationUriPanicCategory, "URI-NORMALIZATION"); +#endif +const TInt KEscapeIndicator = '%'; +const TInt KEscapeTripleLength = 3; +const TInt KEscDelimiterPos = 0; +const TInt KMostSignificantNibblePos = 1; +const TInt KLeastSignificantNibblePos = 2; +const TInt KSubstringLength = 3; +const TInt KUpdateLength = 2; +const TInt KAttachLength = 1; + +const TInt KDotLength = 1; +const TInt KDotDotLength = 2; +const TInt KDotDotSlashLength = 3; +const TInt KSlashDotDotSlashLength = 4; + +// +// +// Implementation of UriUtils +// +// + +/** + Converts a 16-bit format uri into its internet form. Any Unicode characters + are converted into Utf8 representation and then any excluded characters are + escape encoded. Reserved characters specified in RFC2396 will not be escape + encoded however, these include ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". + For example http://localhost will not be encoded to http%3A%2F%2Flocalhost. + + @since 6.0 + @deprecated Deprecated in 9.1 + @leave KUriUtilsCannotConvert. When the input data cannot be converted. + @leave KUriUtilsErr16BitChar. When the input data has a 16-Bit character to be escape encoded. + @param aUri The 16-bit format uri. + @return A pointer to a newly created 8-bit uri. + */ +EXPORT_C CUri8* UriUtils::ConvertToInternetFormL(const TUriC16& aUri) + { + // Need to convert to utf8 + HBufC8* utf8Buf = EscapeUtils::ConvertFromUnicodeToUtf8L(aUri.UriDes()); + CleanupStack::PushL(utf8Buf); + + // Ok need to parse for the uri without the fragment + TUriParser8 parser; + parser.Parse(*utf8Buf); + TPtrC8 uriNoFragment; + parser.UriWithoutFragment(uriNoFragment); + + // Now escape encode the uri without the fragment + HBufC8* escapedBuf = EscapeUtils::EscapeEncodeL(uriNoFragment, EscapeUtils::EEscapeNormal); + CleanupStack::PushL(escapedBuf); + + // Now escape encode the fragment if there is one... + HBufC8* escapedFragmentBuf = NULL; + if( parser.IsPresent(EUriFragment) ) + { + escapedFragmentBuf = EscapeUtils::EscapeEncodeL(parser.Extract(EUriFragment), EscapeUtils::EEscapeNormal); + CleanupStack::PushL(escapedFragmentBuf); + } + + // Parse and then create the CUri8 object + parser.Parse(*escapedBuf); + CUri8* netForm = CUri8::NewL(parser); + + // Set the fragment if there was one... + if( escapedFragmentBuf != NULL ) + { + CleanupStack::PushL(netForm); + netForm->SetComponentL(*escapedFragmentBuf, EUriFragment); + CleanupStack::Pop(netForm); + CleanupStack::PopAndDestroy(escapedFragmentBuf); + } + + // Cleanup and return + CleanupStack::PopAndDestroy(2, utf8Buf); // utf8Buf, escapedBuf + return netForm; + } + +/** + Converts an 8-bit format uri its into display form. Any escape tripes are decoded and + sets of Utf8 format characters are converted into Unicode. + + @since 6.0 + @deprecated Deprecated in 9.1 + @leave KUriUtilsCannotConvert. When the input data cannot be converted. + @param aUri The 8-bit format uri. + @return A pointer to a newly created 16-bit uri. + */ +EXPORT_C CUri16* UriUtils::ConvertToDisplayFormL(const TUriC8& aUri) + { + // Need decode escape triples + HBufC8* unescapedBuf = EscapeUtils::EscapeDecodeL(aUri.UriDes()); + CleanupStack::PushL(unescapedBuf); + + // Now need to convert utf8 to unicode + HBufC16* utf8Buf = EscapeUtils::ConvertToUnicodeFromUtf8L(*unescapedBuf); + CleanupStack::PushL(utf8Buf); + + // Parse and then create the CUri16 object + TUriParser16 parser; + parser.Parse(*utf8Buf); + CUri16* displayForm = CUri16::NewL(parser); + + // Cleanup and return + CleanupStack::PopAndDestroy(2, unescapedBuf); // unescapedBuf, utf8Buf + return displayForm; + } + +/** + Create a new CUri8 object from a Unicode descriptor. + + @param aUri a Unicode string containing the URI to parse. + @return the new CUri8 object + @leave EUriUtilsParserErrInvalidUri if the descriptor is an invalid URI. + */ +EXPORT_C CUri8* UriUtils::CreateUriL(const TDesC& aUri) + { + // convert to UTF8 + HBufC8* unsafe8 = EscapeUtils::ConvertFromUnicodeToUtf8L(aUri); + CleanupStack::PushL(unsafe8); + // escape encode only those characters that cannot be in a URI. assume all %hh are %encoded already + HBufC8* uri8desc = EscapeUtils::ReEscapeEncodeL(*unsafe8); + CleanupStack::PopAndDestroy(unsafe8); + CleanupStack::PushL(uri8desc); + TUriParser8 parser; + // parse the descriptor into a URI, Leave if it cannot be parsed + User::LeaveIfError( parser.Parse(*uri8desc) ); + + CUri8* uri8 = CUri8::NewL(parser); + CleanupStack::PopAndDestroy(uri8desc); + return uri8; + } + +/** + Create a new CAuthority8 object from a Unicode descriptor. + + @param aAuthority a Unicode string containing the Authority to parse. + @return the new CAuthority8 object + @leave EUriUtilsParserErrInvalidUri if the descriptor is an invalid Authority. + */ +EXPORT_C CAuthority8* UriUtils::CreateAuthorityL(const TDesC& aAuthority) + { + // convert to UTF8 + HBufC8* unsafe8 = EscapeUtils::ConvertFromUnicodeToUtf8L(aAuthority); + CleanupStack::PushL(unsafe8); + // escape encode only those characters that cannot be in the authority. assume all %s are %encoded already + HBufC8* authority8desc = EscapeUtils::ReEscapeEncodeL(*unsafe8); + CleanupStack::PopAndDestroy(unsafe8); + CleanupStack::PushL(authority8desc); + TAuthorityParser8 parser; + // parse the descriptor into the authority, Leave if it cannot be parsed + User::LeaveIfError( parser.Parse(*authority8desc) ); + + CAuthority8* authority8 = CAuthority8::NewL(parser); + CleanupStack::PopAndDestroy(authority8desc); + return authority8; + } + +/** + Checks a descriptor for excluded (invalid) characters. Excluded characters include all + control characters (values 0x00 to 0x1F and greater than 0x7F), space (0x20), delimiter + characters ('<', '>', '#', '%', '"') and unwise characters ('{', '}', '|', '\', '^', '[', ']', '`'). + + @since 6.0 + @param aData The descriptor to be checked. + @return A boolean value of ETrue if the descriptor contains invalid + characters, otherwise EFalse. + */ +EXPORT_C TBool UriUtils::HasInvalidChars(const TDesC8& aData) + { + return CheckForExcludedChars(aData); + } + +/** + Checks a descriptor for excluded (invalid) characters. Excluded characters include all + control characters (values 0x00 to 0x1F and greater than 0x7F), space (0x20), delimiter + characters ('<', '>', '#', '%','"') and unwise characters ('{', '}', '|', '\', '^', '[', ']', '`'). + + @since 6.0 + @param aData The descriptor to be checked. + @return A boolean value of ETrue if the descriptor contains invalid + characters, otherwise EFalse. + */ +EXPORT_C TBool UriUtils::HasInvalidChars(const TDesC16& aData) + { + return CheckForExcludedChars(aData); + } + +/** + Checks the supplied host for an IPv4, IPv6 or text format host + + @since 7.0 + @param aHost The descriptor containing the host to check + @return A TUriHostType enum of either EIPv6, EIPv4, EText or EUnknown + */ +EXPORT_C UriUtils::TUriHostType UriUtils::HostType(const TDesC8& aHost) + { + return CheckHostType(aHost); + } + +/** + Checks the supplied host for an IPv4, IPv6 or text format host + + @since 7.0 + @param aHost The descriptor containing the host to check + @return A TUriHostType enum of either EIPv6, EIPv4, EText or EUnknown + */ +EXPORT_C UriUtils::TUriHostType UriUtils::HostType(const TDesC16& aHost) + { + return CheckHostType(aHost); + } + + + +// +// +// Implementation of component internal functions +// +// + +/** + @internalComponent + + Checks whether the given scheme is a network scheme or not + + @param aScheme The descriptor with the scheme. + @return A boolean value of EFalse if the scheme is SIP. For all other schemes returns ETrue. + */ +TBool IsNetworkScheme(const TDesC8& aScheme) + { + TUriSchemeType scheme = SchemeType(aScheme); + if (scheme == ESchemeTypeSip) + { + return EFalse; + } + return ETrue; + } + +/** + @internalComponent + + Checks whether the given scheme is a network scheme or not + + @param aScheme The descriptor with the scheme. + @return A boolean value of EFalse if the scheme is SIP. For all other schemes returns ETrue. + */ +TBool IsNetworkScheme(const TDesC16& aScheme) + { + TUriSchemeType scheme = SchemeType(aScheme); + if (scheme == ESchemeTypeSip) + { + return EFalse; + } + return ETrue; + } + +/** + @internalComponent + + Returns the type of the URIs scheme + + @param aScheme The descriptor with the scheme. + @return The scheme type + */ +TUriSchemeType SchemeType(const TDesC8& aScheme) + { + // Compares the scheme with both sip and sips + if (aScheme.CompareF(KSipScheme8()) == 0 || aScheme.CompareF(KSipsScheme8()) == 0) + { + // there's a match so this is a sip scheme + return ESchemeTypeSip; + } + //Compares the scheme with tel + else if (aScheme.CompareF(KTelScheme8()) == 0) + { + return ESchemeTypeTel; + } + + return ESchemeTypeUnknown; + } + +/** + @internalComponent + + Returns the type of the URIs scheme + + @param aScheme The descriptor with the scheme. + @return The scheme type + */ +TUriSchemeType SchemeType(const TDesC16& aScheme) + { + // Compares the scheme with both sip and sips + if (aScheme.CompareF(KSipScheme()) == 0 || aScheme.CompareF(KSipsScheme()) == 0) + { + // there's a match so this is a sip scheme + return ESchemeTypeSip; + } + + return ESchemeTypeUnknown; + } + +/** + @internalComponent + + Checks that a text host is in a valid form + + @param aHost The descriptor containing the host to check + @return ETrue if the host is valid otherwise EFalse + */ +TBool IsTextHostValid(const TDesC8& aHost) + { + return CheckValidTextHost(aHost); + } + +/** + @internalComponent + + Checks that a text host is in a valid form + + @param aHost The descriptor containing the host to check + @return ETrue if the host is valid otherwise EFalse + */ +TBool IsTextHostValid(const TDesC16& aHost) + { + return CheckValidTextHost(aHost); + } + + +/** + @internalComponent + + Parses a segment of the form name=value and returns the name and value parts + + @param aSegment the name-value segemnt to parse + @param aName the name part that is returned + @param aValue the value part that is returned + */ +void GetNameValuePair(const TDesC8& aSegment, TPtrC8& aName, TPtrC8& aValue) + { + TPtrC8 value; + TInt sepPos = aSegment.Locate(KEqualsSeparator); + if (sepPos != KErrNotFound) + { + aName.Set(aSegment.Left(sepPos)); + value.Set(aSegment.Mid(sepPos+1)); + } + else + { + aName.Set(aSegment); + } + + aValue.Set(value); + } + + +// +// +// Implementation of LOCAL functions +// +// + +/** + Checks the descriptor for any excluded characters. These are characters that + should have been escaped encoded or ocnverted to Utf8 from Unicode. + + @since 6.0 + @param aData The descriptor to be checked. + @return A boolean value of ETrue if the descriptor contains excluded + characters, EFalse if it does not. + */ +template +LOCAL_C TBool CheckForExcludedChars(const TDesCType& aData) + { + // Run through the descriptor + TBool valid = ETrue; + const TInt length = aData.Length(); + TInt i=0; + while( valid && i +LOCAL_C UriUtils::TUriHostType CheckHostType(const TDesCType& aHost) + { + UriUtils::TUriHostType hostType; + + TInt dotCount=0; + TBool colonPresent=EFalse; + TBool numeric=ETrue; + + TInt len = aHost.Length(); + for (TInt ii=0; ii < len && !colonPresent; ++ii) + { + TChar ch(aHost[ii]); + + // host contains a character that is not '0'..'9' or '.' + if ((ch < 48 || ch > 57) && ch != 46) + numeric=EFalse; + + // need to check that IPv4 address has the 3 dots + if (ch == 46) + ++dotCount; + else + if (ch == 58) + colonPresent=ETrue; + } + + if (colonPresent) // if theres a colon, it has to be an IPv6 address + hostType = UriUtils::EIPv6Host; + else + if (numeric && (dotCount==3)) // if its numeric only, and has three seperators... + hostType = UriUtils::EIPv4Host; + else + hostType = UriUtils::ETextHost; + + return hostType; + } + +/** + @internalComponent + + Checks that a text host is in a valid form + + @param aHost The descriptor containing the host to check + @return ETrue if the host is valid otherwise EFalse + */ +template +LOCAL_C TBool CheckValidTextHost(const TDesCType& aHost) + { + TInt len = aHost.Length(); + if (len == 0) + return EFalse; + + // host name can't start with a dot or dash + TChar firstChar(aHost[0]); + if (firstChar == '-' || firstChar == '.') + return EFalse; + + TChar prev = '\0'; + TInt ii; + for (ii=0; ii < len; ii++) + { + TChar ch(aHost[ii]); + + // Valid characters are a-z, 0-9, '-' and '.' + if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '-' && ch != '.') + { + return EFalse; + } + + // dot is the section separator. Check the previous section is not empty + if (ch == '.' && prev == '.') + { + // can't have an empty section + return EFalse; + } + prev = ch; + } + + // host name can't end with a dot or dash + if (prev == '-' || prev == '.') + return EFalse; + + return ETrue; + } + +/** + Supports Syntax-Based Normalization as specifed in section 6.2.2 of RFC3986. + returns a new CUri8 object containing a normalised URI from a parsed URI object. + + @param aUri A reference to a parsed uri object. + @return A pointer to a CUri8 object containing normalised URI. + @leave KErrNoMemory + @internalAll + */ +EXPORT_C CUri8* UriUtils:: NormaliseUriL(const TUriC8& aUri) + { + CUri8* normalisedUri = CUri8::NewLC(aUri); + PercentEncodeL(normalisedUri); + CaseNormaliseL(normalisedUri); + RemoveDotSegmentsL(normalisedUri); + CleanupStack::Pop(normalisedUri); + return normalisedUri; + } + +/** + Performs Case Normalization for CUri8 object as specified + in section 6.2.2.1 of RFC3986. + + @param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer + to CUri8 object with an uri needs to be case normalised and returns with + case normalised. + @leave KErrNoMemory + */ +void CaseNormaliseL(CUri8* aNormalisedUri ) + { + //Case normalise the scheme + DoCaseNormaliseL(aNormalisedUri, EUriScheme); + //Case normalise the Userinfo + DoCaseNormaliseL(aNormalisedUri, EUriUserinfo); + //Case normalise the Host + DoCaseNormaliseL(aNormalisedUri, EUriHost); + //Case normalise the Port + DoCaseNormaliseL(aNormalisedUri, EUriPort); + //Case normalise the Path + DoCaseNormaliseL(aNormalisedUri, EUriPath); + //Case normalise the Query + DoCaseNormaliseL(aNormalisedUri, EUriQuery); + //Case normalise the Fragment + DoCaseNormaliseL(aNormalisedUri, EUriFragment); + } + +/** + Performs Case Normalization for specified sub component of URI. + + @param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer + to CUri8 object with an uri needs to be case normalised and returns with + case normalised for specified sub component. + @param aComponent Enumeration of TUriComponent. + @leave KErrNoMemory +*/ +void DoCaseNormaliseL(CUri8* aNormalisedUri, TUriComponent aComponent) + { + const TUriC8& uri(aNormalisedUri->Uri()); + if(!uri.IsPresent(aComponent) ) + { + return; + } + //extracts subcomponent of uri which needs to be case-normalised + HBufC8* heapBuf = uri.Extract(aComponent).AllocLC(); + TPtr8 normalisedComponent(heapBuf->Des()); + TBool normalised = EFalse; + if(aComponent == EUriScheme || aComponent == EUriHost ) + { + //change this component to lower case + normalisedComponent.LowerCase(); + normalised = ETrue; + } + + TInt len = normalisedComponent.Length(); + TBuf8 subString; + //case normalise the component + for (TInt pos = 0; pos < len; pos++) + { + if (normalisedComponent[pos] == KEscapeIndicator ) + { + __ASSERT_DEBUG( ((len-pos) >= KSubstringLength), User::Panic(KNormalisationUriPanicCategory, KUriUtilsErrBadEscapeTriple) ); + TPtrC8 componentBuf(normalisedComponent.Mid(pos,KSubstringLength)); + if (ValidateAndConvertPercentEncodedTriple(componentBuf,subString)) + { + normalisedComponent.Replace(pos,KSubstringLength,subString); + pos += KUpdateLength; + normalised = ETrue; + subString.Zero(); + } + } + } + + //updating the uri with normalised string + if( normalised ) + { + if(aComponent=EUriScheme) + { + aNormalisedUri->SetComponentL(normalisedComponent, aComponent); + } + else + { + User::Leave(KErrArgument); + } + + } + CleanupStack::PopAndDestroy(heapBuf); + } + +/** + Validates and Converts the valid Percent encoded triplets to Uppercase for specified + sub component of URI. For eg: Converts %3a to %3A + + @param aData A reference to a string to be validated and converted to upper case. + @param aCaseNormalizedData A reference to a descriptor that is converted to + uppercase that is to be returned. + @return returns a bool whether it is a valid Percent encoded triplet +*/ +TBool ValidateAndConvertPercentEncodedTriple(TDesC8& aData , TDes8& aCaseNormalizedData ) + { + // See if the descriptor is actually long enough and + // Check that the three characters form an escape triple - first char is '%' + if( aData.Length() < KEscapeTripleLength || aData[KEscDelimiterPos] != KEscapeIndicator ) + { + return EFalse;//do nothing + } + + // Check that next two characters are valid + TInt mostSignificantDigitValue = KHexDigit().LocateF(aData[KMostSignificantNibblePos] ); + TInt leastSignificantDigitValue = KHexDigit().LocateF(aData[KLeastSignificantNibblePos] ); + + if( mostSignificantDigitValue== KErrNotFound || leastSignificantDigitValue == KErrNotFound ) + { + // Either of the characters were not a valid hex character + return EFalse; + } + aCaseNormalizedData.Zero(); + aCaseNormalizedData.Append(KEscapeIndicator); + + //Coverts most significant hex character to uppercase + (mostSignificantDigitValue >= 0 && mostSignificantDigitValue <= 0xF) ? + aCaseNormalizedData.Append(KHexDigit().Mid(mostSignificantDigitValue,1)) : + aCaseNormalizedData.Append(KHexDigit().Mid(mostSignificantDigitValue,1)); + + //Coverts least significant hex character to uppercase + (leastSignificantDigitValue >= 0 && leastSignificantDigitValue <= 0xF) ? + aCaseNormalizedData.Append(KHexDigit().Mid(leastSignificantDigitValue,1)) : + aCaseNormalizedData.Append(aData[KLeastSignificantNibblePos]); + + return ETrue; + } + +/** + Performs Percent-Encoding Normalization for CUri8 object as specifed in + section 6.2.2.2 of RFC3986. + + @param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer to + CUri8 object with an uri needs to be Percent-Encoded and returns with Percent-Encode + normalised form. + @leave KErrNoMemory + */ +void PercentEncodeL(CUri8* aNormalisedUri) + { + //PercentEncode the scheme + DoPercentEncodeL(aNormalisedUri, EUriScheme); + //PercentEncode the Userinfo + DoPercentEncodeL(aNormalisedUri, EUriUserinfo); + //PercentEncode the Host + DoPercentEncodeL(aNormalisedUri, EUriHost); + //PercentEncode the Port + DoPercentEncodeL(aNormalisedUri, EUriPort); + //PercentEncode the Path + DoPercentEncodeL(aNormalisedUri, EUriPath); + //PercentEncode the Query + DoPercentEncodeL(aNormalisedUri, EUriQuery); + //PercentEncode the Fragment + DoPercentEncodeL(aNormalisedUri, EUriFragment); + } + +/** + Performs Percent-Encoding for specified sub component of URI. + + @param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer to + CUri8 object with an uri needs to be Percent-Encoded and returns with Percent-Encoded + for specified sub component. + @param aComponent Enumeration of TUriComponent. + @leave KErrNoMemory +*/ +void DoPercentEncodeL(CUri8* aNormalisedUri, TUriComponent aComponent) + { + const TUriC8& uri(aNormalisedUri->Uri()); + if(!uri.IsPresent(aComponent)) + { + return; + } + + HBufC8* heapBuf = uri.Extract(aComponent).AllocLC(); + TPtr8 percentNormalisedComponent(heapBuf->Des()); + TBool normalised = EFalse; + TInt len = percentNormalisedComponent.Length(); + for (TInt pos = 0; pos < len; pos++) + { + TInt hex; + // check for and decode '%' encoded characters + if (percentNormalisedComponent[pos] == KEscapeIndicator && EscapeUtils::IsEscapeTriple(percentNormalisedComponent.Mid(pos, KSubstringLength), hex)) + { + TChar replacedChar(hex); + if( KUnreserved().LocateF(hex) != KErrNotFound || replacedChar.IsAlphaDigit() ) + { + TBuf8 subString; + subString.Append(replacedChar); + percentNormalisedComponent.Replace(pos, KSubstringLength, subString); + normalised = ETrue; + len = percentNormalisedComponent.Length(); + } + } + } + if( normalised ) + { + if(aComponent=EUriScheme) + { + aNormalisedUri->SetComponentL(percentNormalisedComponent, aComponent); + } + else + { + User::Leave(KErrArgument); + } + + } + CleanupStack::PopAndDestroy(heapBuf); + } + +/** + Performs Path Segment Normalization for CUri8 object as specifed in + section 6.2.2.3 of RFC3986. + + @param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer to + CUri8 object with uri needs to be Path Segment normalised and returns with + Path Segment normalised form. + @leave KErrNoMemory + */ +void RemoveDotSegmentsL(CUri8* aNormalisedUri) + { + const TUriC8& uri( aNormalisedUri->Uri() ); + if(uri.IsPresent(EUriPath)) + { + HBufC8* dotSegmentsPath = uri.Extract(EUriPath).AllocLC(); + RemoveExtraneousDotSegmentsL(dotSegmentsPath); + aNormalisedUri->SetComponentL(*dotSegmentsPath, EUriPath); + CleanupStack::PopAndDestroy(dotSegmentsPath); + } + } + +/** + Performs Remove_dot_segments algorithm as specifed in section 5.2.4 of RFC3986. + + @param aUriInputPath It is an in-out parameter. aUriInputPath is a pointer to the + path descriptor to be normalised for extraneous dot_segments and returns with + normalised dot_segments. + @leave KErrNoMemory +*/ +void RemoveExtraneousDotSegmentsL(HBufC8* aUriInputPath) + { + TPtr8 uriPathBuf(aUriInputPath->Des()); + TInt length = uriPathBuf.Length(); + HBufC8* path = HBufC8::NewLC(length); + TPtr8 transitionalBuf(path->Des()); + + while(length > 0) + { + //step a of section 5.2.4 of RFC 3986 + if(length >= KDotDotSlashLength && + KDotDotSlash().Compare(uriPathBuf.Mid(0, KDotDotSlashLength)) == 0 ) + { + uriPathBuf.Delete(0,KDotDotSlashLength); + } + //step a of section 5.2.4 of RFC 3986 + else if(length >= KDotDotLength && + KDotSlash().Compare(uriPathBuf.Mid(0, KDotDotLength)) == 0) + { + uriPathBuf.Delete(0,KDotDotLength); + } + //step b of section 5.2.4 of RFC 3986 + else if(length >= KDotDotSlashLength && + KSlashDotSlash().Compare(uriPathBuf.Mid(0, KDotDotSlashLength)) == 0) + { + uriPathBuf.Replace(0, KDotDotSlashLength, KSlash); + } + //step c of section 5.2.4 of RFC 3986 + else if(length >= KSlashDotDotSlashLength && + KSlashDotDotSlash().Compare(uriPathBuf.Mid(0, KSlashDotDotSlashLength)) == 0) + { + updateStrings(uriPathBuf, transitionalBuf, KSlashDotDotSlashLength); + } + //step c of section 5.2.4 of RFC 3986 --complete path segment + else if(length == KDotDotSlashLength && + KSlashDotDot().Compare(uriPathBuf.Mid(0, KDotDotSlashLength)) == 0) + { + updateStrings(uriPathBuf, transitionalBuf, KDotDotSlashLength); + } + //step b of section 5.2.4 of RFC 3986--complete path segment + else if(length == KDotDotLength && + KSlashDot().Compare(uriPathBuf.Mid(0, KDotDotLength)) == 0) + { + uriPathBuf.Replace(0, KDotDotLength, KSlash); + } + //step d of section 5.2.4 of RFC 3986 + else if(length == KDotDotLength && + KDotDot().Compare(uriPathBuf.Mid(0)) == 0) + { + uriPathBuf.Delete(0,KDotDotLength); + } + //step d of section 5.2.4 of RFC 3986 + else if(length == KDotLength && + KDot().Compare(uriPathBuf.Mid(0)) == 0) + { + uriPathBuf.Delete(0,KDotLength); + } + //step e of section 5.2.4 of RFC 3986 + else + { + //get the first path segment including initial / (if any)from uriPathBuf + // till next slash (but not including next slash)..append it to the output Buf + TInt substrLength; + TInt nextSlashPos = uriPathBuf.Find(KSlash); + if(nextSlashPos == 0 && length > KDotLength) + //replace with locate next + { + nextSlashPos = uriPathBuf.Mid(1).Find(KSlash); + if(nextSlashPos != KErrNotFound) + { + ++nextSlashPos; + } + } + if(length == KDotLength) + //only '/' is exist + { + substrLength = length; + } + else + { + substrLength = nextSlashPos == KErrNotFound ? length : nextSlashPos ; + } + transitionalBuf.Append(uriPathBuf.Mid(0,substrLength)); + uriPathBuf.Delete(0,substrLength); + } + length = uriPathBuf.Length(); + } + uriPathBuf.Copy(transitionalBuf); + CleanupStack::PopAndDestroy(path); + } + +/** + Updates the strings specified in step c of section 5.2.4 of RFC 3986 + + @param aInputBuf A reference to the inputBuf needs to be modified + @param aOutPutBuf A reference to the outPutBuf needs to be modified + @param aLength length of the string to be replaced. + */ +void updateStrings(TPtr8& aInputBuf, TPtr8& aOutPutBuf, TInt aLength) + { + aInputBuf.Replace(0,aLength,KSlash); + + //In outPutBuf to remove the last segment starting with / (if exist) + //eg: /abc/def/fgh --> /abc/def + TInt outputBufLength = aOutPutBuf.Length(); + TInt pos = aOutPutBuf.LocateReverse('/'); + //remove the last segment including '/' + pos != KErrNotFound ? aOutPutBuf.Delete( pos, outputBufLength - pos ) : aOutPutBuf.Delete( 0,outputBufLength ); + } +