diff -r f5050f1da672 -r 04becd199f91 javacommons/gcfbase/src.s60/turi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javacommons/gcfbase/src.s60/turi.cpp Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,475 @@ +/* +* Copyright (c) 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: URI parser specific to symbian +* +*/ + + +#include "turi.h" + + + +const TInt KMinSizeOfEqualsAndValue = 2; +const TUint16 KCharColon = ':'; +const TUint16 KCharSemiColon = ';'; +const TUint16 KCharForwardSlash = '/'; +const TUint16 KCharEquals = '='; +const TUint16 KCharQuestionMark = '?'; +_LIT(KSlashes, "//"); +_LIT(KIPv6PrefixForIPv4MappedAddress, "::ffff:"); +_LIT(KParamValueTrue, "true"); +_LIT(KParamValueFalse, "false"); + + + +// ---------------------------------------------------------------------------- +// TUri +// + +/** +There is not much else to distinguish the most basic URI from other strings, +so all we test here is if it contains a colon. +*/ +TBool TUri::IsUri(const TDesC16& aName) +{ + return (aName.Locate(KCharColon) > 0); +} + + + +/** +Parses a URI, based on the format detailed in RFC 2396, e.g. +://? +or more generally: +: +if aCheckForSlashes is ETrue and scheme-specific-part +doesn't start with 2 slashes, Parse returns KErrArgument +*/ +TInt TUri::Parse(const TDesC16& aDes , TBool aCheckForSlashes) +{ + iScheme.Set(KNullDesC()); + iSchemeData.Set(KNullDesC()); + iHost.Set(KNullDesC()); + iPort.Set(KNullDesC()); + iPath.Set(KNullDesC()); + iParameters.Set(KNullDesC()); + iQuery.Set(KNullDesC()); + + // Set this descriptor to equal the given URI + Set(aDes); + // Ensure that the colon is present and determine the scheme and scheme-specific + // part + TInt colonIndex = Locate(KCharColon); + // The scheme must not be empty + if (colonIndex <= 0) + { + return KErrArgument; + } + iScheme.Set(Left(colonIndex)); + iSchemeData.Set(Mid(colonIndex + 1)); + + // Parse the scheme data further - we assume it is going to start with 2 slashes + // and may contain stuff like a host, port, path, parameters. If it does not + // have 2 slashes we do no more parsing. + if (iSchemeData.Find(KSlashes()) == 0) + { + TPtrC16 portionToParse(iSchemeData.Mid(KSlashes().Length())); + + // Parse location (host and port) + TInt pathStartIndex = portionToParse.Locate(KCharForwardSlash); + TInt parametersStartIndex = portionToParse.Locate(KCharSemiColon); + TInt queryStartIndex = portionToParse.Locate(KCharQuestionMark); + // Find the length of the location portion of the URI + TInt locationLength = portionToParse.Length(); + if (pathStartIndex != KErrNotFound) + { + locationLength = pathStartIndex; + } + else if (parametersStartIndex != KErrNotFound) + { + locationLength = parametersStartIndex; + } + else if (queryStartIndex != KErrNotFound) + { + locationLength = queryStartIndex; + } + // Extract the host and port from the location portion, separated by a colon + const TPtrC16 location(portionToParse.Left(locationLength)); + // handle the case of an IPv4-mapped address, like ::ffff:10.10.10.10 + TPtrC16 IPv4Location; + TInt prefixLength = 0; + if (location.FindF(KIPv6PrefixForIPv4MappedAddress()) == 0) + { + prefixLength = KIPv6PrefixForIPv4MappedAddress().Length(); + IPv4Location.Set(location.Mid(prefixLength)); + } + else + { + IPv4Location.Set(location); + } + TInt locationColonIndex = IPv4Location.Locate(KCharColon); + if (locationColonIndex != KErrNotFound) + { + iHost.Set(location.Left(prefixLength + locationColonIndex)); + iPort.Set(IPv4Location.Mid(locationColonIndex + 1)); + } + else + { + iHost.Set(location); + } + + // Parse path (and Query) + if (pathStartIndex != KErrNotFound) + { + // Skip past the '/' character that marks the start of the path + portionToParse.Set(portionToParse.Mid(locationLength + 1)); + } + queryStartIndex = portionToParse.Locate(KCharQuestionMark); + if (queryStartIndex != KErrNotFound) + { + iQuery.Set(portionToParse.Mid(queryStartIndex + 1)); + portionToParse.Set(portionToParse.Left(queryStartIndex)); + } + if (pathStartIndex != KErrNotFound) + { + iPath.Set(portionToParse); + } + + // Parse parameters + parametersStartIndex = portionToParse.Locate(KCharSemiColon); + if (parametersStartIndex != KErrNotFound) + { + // Do not skip the ';' character that marks the start of the parameters + iParameters.Set(portionToParse.Mid(parametersStartIndex)); + } + + } + else + { + if (aCheckForSlashes) + return KErrArgument; + else + { + //not checking for slashes, but do expect there to be parameters + //used for CommConnection URIs + TInt parametersStartIndex = iSchemeData.Locate(KCharSemiColon); + if (parametersStartIndex != KErrNotFound) + { + iPort.Set(iSchemeData.Left(parametersStartIndex)); + // Do not skip the ';' character that marks the start of the parameters + iParameters.Set(iSchemeData.Mid(parametersStartIndex)); + } + else + { + iPort.Set(iSchemeData); + } + } + } + return KErrNone; +} + + + +TInt TUri::PortAsUint(TUint& aPortNum) const +{ + if (iPort.Length() == 0) + { + return KErrNotFound; + } + TLex16 portParser(iPort); + TInt error = portParser.Val(aPortNum); + // Check that the whole port string was parsed to a number + if (error != KErrNone || !portParser.Eos()) + { + return KErrArgument; + } + return KErrNone; +} + + + +/** +Looks for the boolean value of the named parameter. +@param aParamName The name of the boolean parameter. +@param aValue The value that is set to the value of the parameter. This is +not changed if an error code is returned. +@return KErrNotFound if the parameter is not defined, KErrArgument if there +is a parsing error, otherwise KErrNone. +*/ +TInt TUri::GetParameterValue(const TDesC16& aParamName, TBool& aValue) const +{ + // Assign default value + TBool value; + TPtrC16 paramValue; + TInt error = GetParameterValue(aParamName, paramValue); + if (error != KErrNone) + { + return error; + } + if (paramValue.CompareF(KParamValueTrue()) == 0) + { + value = ETrue; + } + else if (paramValue.CompareF(KParamValueFalse()) == 0) + { + value = EFalse; + } + else + { + return KErrArgument; + } + aValue = value; + return KErrNone; +} + + + +/** +Looks for the integer value of the named parameter. If the parameter is +not found, it dos not change the value of aValue. +@return KErrNotFound if the parameter is not defined, KErrArgument if there +is a parsing error, otherwise KErrNone. +*/ +TInt TUri::GetParameterValueInt(const TDesC16& aParamName, TInt& aValue) const +{ + TPtrC16 paramValue; + TInt error = GetParameterValue(aParamName, paramValue); + if (error != KErrNone) + { + return error; + } + TLex16 numberParser(paramValue); + TInt value; + error = numberParser.Val(value); + if (error != KErrNone) + { + return KErrArgument; + } + aValue = value; + return KErrNone; +} + + + +TInt TUri::GetParameterValue(const TDesC16& aParamName, TPtrC16& aValue) const +{ + __ASSERT_DEBUG(aParamName.Length() > 0, User::Invariant()); + + TInt index = FindParamNameIndex(aParamName, iParameters); + if (index < KErrNone) + { + return index; + } + // We know the value is defined in the parameter list + // Ensure that the parameter is defined only once in the list + TPtrC16 restOfParameterList(iParameters.Mid(index + aParamName.Length())); + TInt secondParamIndex = FindParamNameIndex(aParamName, restOfParameterList); + if (secondParamIndex >= KErrNone) + { + // Parameter is defined twice, which is invalid + return KErrArgument; + } + // Skip over the name and equals sign + index += aParamName.Length(); + ++index; + // Extract the value itself + const TPtrC16 remainder(iParameters.Mid(index)); + TInt nextSemiColonIndex = remainder.Locate(KCharSemiColon); + TInt paramValueLength = (nextSemiColonIndex != KErrNotFound) ? + nextSemiColonIndex : iParameters.Length(); + aValue.Set(remainder.Left(paramValueLength)); + return KErrNone; +} + + + +/** +Finds the index of the parameter name. Checks that there are enough characters +after the name for the equals sign and a value of length 1, and that the name +has a semi-colon in front and an equals after it. +*/ +TInt TUri::FindParamNameIndex(const TDesC16& aParamName, + const TDesC16& aParametersSegment) const +{ + TPtrC16 parameters(aParametersSegment); + TInt nameIndex = KErrNotFound; + TInt paramSegmentIndex = 0; + do + { +// DEBUG( "TUri::GetParameterValue(): finding param name: %S", &aParamName ); + // FindF is used because the case is not relevant for data within the URI + TInt index = parameters.FindF(aParamName); + if (index == KErrNotFound) + { + return KErrNotFound; + } + + TInt endOfParamNameIndex = index + aParamName.Length(); + // Check there are enough extra characters after the parameter name for the + // equals and value + TPtrC16 afterParamNameString(parameters.Mid(endOfParamNameIndex)); + if (afterParamNameString.Length() < KMinSizeOfEqualsAndValue) + { + return KErrArgument; + } + + // Check the parameter name found is a complete name and not part of a + // larger string, i.e. it has a semi-colon in front and an equals after + if (index == 0 || parameters[index - 1] != KCharSemiColon || + parameters[endOfParamNameIndex] != KCharEquals) + { + paramSegmentIndex += endOfParamNameIndex; + parameters.Set(parameters.Mid(endOfParamNameIndex)); + } + else + { + nameIndex = paramSegmentIndex + index; + } + } + while (nameIndex == KErrNotFound); + return nameIndex; +} + + + +/** +Iterates through the parameters of the URI, checking that each parameter name is +present in the supplied list of valid names. +@return KErrNone if all parameter names match the legal ones, or if there are +no parameters in the URI, as parameters are optional anyway. +*/ +TInt TUri::CheckParameterValidity(const RPointerArray& aLegalParams) const +{ + if (iParameters.Length() == 0) + { + return KErrNone; + } + TPtrC16 remainder(iParameters); + TInt semiColonIndex = 0; + do + { + remainder.Set(remainder.Mid(semiColonIndex + 1)); + TInt error = CheckParameter(aLegalParams, remainder); + if (error != KErrNone) + { + return error; + } + semiColonIndex = remainder.Locate(KCharSemiColon); + } + while (semiColonIndex != KErrNotFound); + return KErrNone; +} + + + +/** +Checks that the parameter name at the start of aRemainder is present in the +list of legal parameters. +*/ +TInt TUri::CheckParameter(const RPointerArray& aLegalParams, + const TDesC16& aRemainder) const +{ + // Find the end of the parameter name + TInt equalsIndex = aRemainder.Locate(KCharEquals); + if (equalsIndex == KErrNotFound) + { + return KErrArgument; + } + // Search for the name in the legal names list + TPtrC16 paramName(aRemainder.Left(equalsIndex)); + TIdentityRelation relation(&TUri::MatchParamName); + TInt nameIndex = aLegalParams.Find(¶mName, relation); + if (nameIndex == KErrNotFound) + { + return KErrArgument; + } + return KErrNone; +} + + + +/** +Utility method for use with RArray::Find(). +*/ +TBool TUri::MatchParamName(const TDesC16& aName1, const TDesC16& aName2) +{ + return (aName1.CompareF(aName2) == 0); +} + + + +/** +Check there are no duplicate parameters +*/ +TInt TUri::CheckNoDuplicateParameters() const +{ + if (iParameters.Length() == 0) + { + return KErrNone; + } + + RArray parameters; + TPtrC16 remainder(iParameters); + TInt semiColonIndex = 0; + do + { + remainder.Set(remainder.Mid(semiColonIndex + 1)); + + TInt equalsIndex = remainder.Locate(KCharEquals); + if (equalsIndex == KErrNotFound) + { + parameters.Close(); + return KErrArgument; + } + + TPtrC16 paramName(remainder.Left(equalsIndex)); + + TIdentityRelation relation(&TUri::MatchParamNamePtr); + TInt nameIndex = parameters.Find(paramName, relation); + + TInt error = KErrNone; + if (nameIndex == KErrNotFound) + { + error = parameters.Append(paramName); + } + else if (nameIndex >= 0) + { + error = KErrAlreadyExists; + } + else + { + error = nameIndex; + } + + if (error != KErrNone) + { + parameters.Close(); + return error; + } + semiColonIndex = remainder.Locate(KCharSemiColon); + } + while (semiColonIndex != KErrNotFound); + + parameters.Close(); + return KErrNone; +} + + +/** +Utility method for use with RArray::Find(). +*/ +TBool TUri::MatchParamNamePtr(const TPtrC16& aName1, const TPtrC16& aName2) +{ + return (aName1.CompareF(aName2) == 0); +}