--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/genericservices/httputils/UriParser/TEquiv.cpp Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,447 @@
+// 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:
+//
+
+#include "TEquiv.h"
+#include <uriutils.h>
+#include <uriutilscommon.h>
+#include "UriUtilsInternal.h"
+#include <delimitedpathsegment8.h>
+#include <delimitedquery8.h>
+#include <escapeutils.h>
+
+_LIT8(KParamUserFull, ";user=");
+_LIT8(KParamTtlFull, ";ttl=");
+_LIT8(KParamMethodFull, ";method=");
+_LIT8(KParamMaddrFull, ";maddr=");
+_LIT8(KParamMaddr, "maddr");
+
+_LIT8(KHeaderId, "call-id");
+_LIT8(KHeaderIdAbbr, "i");
+_LIT8(KHeaderContact, "contact");
+_LIT8(KHeaderContactAbbr, "m");
+_LIT8(KHeaderEncoding, "content-encoding");
+_LIT8(KHeaderEncodingAbbr, "e");
+_LIT8(KHeaderLength, "content-length");
+_LIT8(KHeaderLengthAbbr, "l");
+_LIT8(KHeaderType, "content-type");
+_LIT8(KHeaderTypeAbbr, "c");
+_LIT8(KHeaderFrom, "from");
+_LIT8(KHeaderFromAbbr, "f");
+_LIT8(KHeaderSubject, "subject");
+_LIT8(KHeaderSubjectAbbr, "s");
+_LIT8(KHeaderTo, "to");
+_LIT8(KHeaderToAbbr, "t");
+
+TEquiv::TEquiv(const TUriC8& aLhs, const TUriC8& aRhs)
+: iLhs(aLhs), iRhs(aRhs)
+ {
+ }
+
+TBool TEquiv::EquivalentL() const
+ {
+ if (!IsMatchSchemeL())
+ return KUriUtilsErrDifferentScheme;
+
+ if (!IsMatchUserInfoL())
+ return KUriUtilsErrDifferentUserInfo;
+
+ if (!IsMatchHostL())
+ return KUriUtilsErrDifferentHost;
+
+ if (!IsMatchPortL())
+ return KUriUtilsErrDifferentPort;
+
+ if (!IsMatchPathL())
+ return KUriUtilsErrDifferentPath;
+
+ if (!IsMatchQueryL())
+ return KUriUtilsErrDifferentQuery;
+
+ if (!IsMatchFragmentL())
+ return KUriUtilsErrDifferentFragment;
+
+ return KErrNone;
+ }
+
+TBool TEquiv::IsMatchSchemeL() const
+ {
+ HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriScheme);
+ HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriScheme);
+ TBool result = IsMatchCaseless(*lhsDes, *rhsDes);
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+TBool TEquiv::IsMatchUserInfoL() const
+ {
+ HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriUserinfo);
+ HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriUserinfo);
+ TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+TBool TEquiv::IsMatchHostL() const
+ {
+ HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost);
+ HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost);
+ TBool result = IsMatchCaseless(*lhsDes, *rhsDes);
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+TBool TEquiv::IsMatchPortL() const
+ {
+ HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPort);
+ HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPort);
+ TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+TBool TEquiv::IsMatchPathL() const
+ {
+ HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPath);
+ HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPath);
+ TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+TBool TEquiv::IsMatchQueryL() const
+ {
+ HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriQuery);
+ HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriQuery);
+ TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+TBool TEquiv::IsMatchFragmentL() const
+ {
+ HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriFragment);
+ HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriFragment);
+ TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+HBufC8* TEquiv::DecodedSegmentLC(const TUriC8& aUri, TUriComponent aSegmentType) const
+ {
+ HBufC8* decoded = EscapeUtils::EscapeDecodeL(aUri.Extract(aSegmentType));
+ CleanupStack::PushL(decoded);
+ return decoded;
+ }
+
+TEquivSip::TEquivSip(const TUriC8& aLhs, const TUriC8& aRhs)
+: TEquiv(aLhs, aRhs)
+ {
+ }
+
+void TEquivSip::RemoveLeadingZeros(TPtr8 aHost) const
+ {
+ for (TInt i=0; i < aHost.Length(); i++)
+ {
+ TBool startOfNumber = (i == 0 || aHost[i-1] < '0' || aHost[i-1] > '9');
+ if (aHost[i] == '0' && startOfNumber)
+ {
+ // The character is a zero and is either at the start of the string
+ // or the fist number in a sequence.
+ aHost.Delete(i--,1);
+ }
+ }
+ }
+
+TBool TEquivSip::IsMatchHostL(const TDesC8& aLhs, const TDesC8& aRhs) const
+ {
+ UriUtils::TUriHostType lhsType = UriUtils::HostType(aLhs);
+ UriUtils::TUriHostType rhsType = UriUtils::HostType(aRhs);
+ if (lhsType != rhsType)
+ return EFalse;
+ if (lhsType != UriUtils::ETextHost)
+ {
+ // Host is IPv4 or IPv6
+ // Create a copy of the hosts and remove any leading '0's
+ HBufC8* lhsCopy = aLhs.AllocLC();
+ HBufC8* rhsCopy = aRhs.AllocLC();
+ RemoveLeadingZeros(lhsCopy->Des());
+ RemoveLeadingZeros(rhsCopy->Des());
+ TBool result = IsMatchCaseSensitive(*lhsCopy, *rhsCopy);
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+ return IsMatchCaseless(aLhs, aRhs);
+ }
+
+TBool TEquivSip::IsMatchHostL() const
+ {
+ HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost);
+ HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost);
+ TBool result = IsMatchHostL(*lhsDes, *rhsDes);
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+TBool TEquivSip::IsParamCompatibleL(const TDesC8& aLhsName, const TDesC8& aLhsValue, const TDesC8& aRhsName, const TDesC8& aRhsValue) const
+ {
+ // Were're just checking that if the segments have the same name part
+ // that their values are the same. This method only returns false if the lhs and rhs
+ // have the same name but their values are different.
+ if (!IsMatchCaseless(aLhsName, aRhsName))
+ {
+ // Names don't match so we're OK
+ return ETrue;
+ }
+
+ // The maddr parameter needs to be handled differently from the others
+ // The address is checked for equivalence not just a straight string compare.
+ if (IsMatchCaseless(aLhsName, KParamMaddr))
+ {
+ return IsMatchHostL(aLhsValue, aRhsValue);
+ }
+ else
+ {
+ if (!IsMatchCaseless(aLhsValue, aRhsValue))
+ {
+ // Names are the same but the values are different
+ // We have a incompatible parameter
+ return EFalse;
+ }
+ }
+
+ return ETrue;
+ }
+
+TBool TEquivSip::IsParamListCompatibleL(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const
+
+ {
+ TPtrC8 lhsName;
+ TPtrC8 lhsValue;
+ TPtrC8 rhsName;
+ TPtrC8 rhsValue;
+
+ TPtrC8 lhsSegment;
+ TPtrC8 rhsSegment;
+
+ // roll back to the start of the lhs segment parser
+ aLhsParser.Reset();
+
+ while( aLhsParser.GetNext(lhsSegment) == KErrNone )
+ {
+ // roll back to the start of the rhs segment parser
+ aRhsParser.Reset();
+
+ GetNameValuePair(lhsSegment, lhsName, lhsValue);
+ while( aRhsParser.GetNext(rhsSegment) == KErrNone )
+ {
+ GetNameValuePair(rhsSegment, rhsName, rhsValue);
+ if (!IsParamCompatibleL(lhsName, lhsValue, rhsName, rhsValue))
+ return EFalse;
+ }
+ }
+
+ return ETrue;
+ }
+
+TInt TEquivSip::ListLength(const TDelimitedParserBase8& aParser) const
+ {
+ aParser.Reset();
+
+ TInt result = 0;
+ while (!aParser.Eos())
+ {
+ aParser.Inc();
+ ++result;
+ }
+
+ aParser.Reset();
+ return result;
+ }
+
+TBool TEquivSip::IsMatchPathL() const
+ {
+ HBufC8* lhs = DecodedSegmentLC(iLhs, EUriPath);
+ HBufC8* rhs = DecodedSegmentLC(iRhs, EUriPath);
+
+ TDelimitedPathSegmentParser8 lhsParser;
+ lhsParser.Parse(*lhs);
+ TDelimitedPathSegmentParser8 rhsParser;
+ rhsParser.Parse(*rhs);
+
+ // Check each parameter in the lhs parameter list with those in
+ // the rhs parameter list. If at any point a parameter is incompatible
+ // we'll return false.
+ TBool result = ETrue;
+
+ // Alway check the parameter list with the most parameters against the other
+ // so that we don't miss any
+ TInt lhsLength = ListLength(lhsParser);
+ TInt rhsLength = ListLength(rhsParser);
+
+ if (lhsLength > rhsLength)
+ {
+ result = IsParamListCompatibleL(lhsParser, rhsParser);
+ }
+ else
+ {
+ result = IsParamListCompatibleL(rhsParser, lhsParser);
+ }
+
+ // check that the special parameters, if present, are present in both
+ if (result)
+ {
+ if ((lhs->Find(KParamUserFull) == KErrNotFound) != (rhs->Find(KParamUserFull) == KErrNotFound) ||
+ (lhs->Find(KParamTtlFull) == KErrNotFound) != (rhs->Find(KParamTtlFull) == KErrNotFound) ||
+ (lhs->Find(KParamMethodFull) == KErrNotFound) != (rhs->Find(KParamMethodFull) == KErrNotFound) ||
+ (lhs->Find(KParamMaddrFull) == KErrNotFound) != (rhs->Find(KParamMaddrFull) == KErrNotFound) )
+ {
+ result = EFalse;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+
+TEquivSip::THeaderType TEquivSip::HeaderType(const TDesC8& aHeaderName) const
+ {
+ if (IsMatchCaseless(aHeaderName, KHeaderId) || IsMatchCaseless(aHeaderName, KHeaderIdAbbr))
+ return EHeaderId;
+ if (IsMatchCaseless(aHeaderName, KHeaderContact) || IsMatchCaseless(aHeaderName, KHeaderContactAbbr))
+ return EHeaderContact;
+ if (IsMatchCaseless(aHeaderName, KHeaderEncoding) || IsMatchCaseless(aHeaderName, KHeaderEncodingAbbr))
+ return EHeaderEncoding;
+ if (IsMatchCaseless(aHeaderName, KHeaderLength) || IsMatchCaseless(aHeaderName, KHeaderLengthAbbr))
+ return EHeaderLength;
+ if (IsMatchCaseless(aHeaderName, KHeaderType) || IsMatchCaseless(aHeaderName, KHeaderTypeAbbr))
+ return EHeaderType;
+ if (IsMatchCaseless(aHeaderName, KHeaderFrom) || IsMatchCaseless(aHeaderName, KHeaderFromAbbr))
+ return EHeaderFrom;
+ if (IsMatchCaseless(aHeaderName, KHeaderSubject) || IsMatchCaseless(aHeaderName, KHeaderSubjectAbbr))
+ return EHeaderSubject;
+ if (IsMatchCaseless(aHeaderName, KHeaderTo) || IsMatchCaseless(aHeaderName, KHeaderToAbbr))
+ return EHeaderTo;
+
+ return EHeaderNormal;
+ }
+
+TBool TEquivSip::IsMatchHeader(const TDesC8& aLhs, const TDesC8& aRhs) const
+ {
+ if (IsMatchCaseless(aLhs, aRhs))
+ {
+ // identical headers are always OK
+ return ETrue;
+ }
+
+ // We now need to check for abbreviated headers
+ TPtrC8 lhsName;
+ TPtrC8 lhsValue;
+ TPtrC8 rhsName;
+ TPtrC8 rhsValue;
+
+ GetNameValuePair(aLhs, lhsName, lhsValue);
+ GetNameValuePair(aRhs, rhsName, rhsValue);
+
+ if (!IsMatchCaseless(lhsValue, rhsValue))
+ {
+ // headers with different values can never match
+ return EFalse;
+ }
+
+ // We now have only those with different header names but with the same value
+ // The last check is to see if the headers are in abbreviated forms
+ THeaderType lhsType = HeaderType(lhsName);
+ THeaderType rhsType = HeaderType(rhsName);
+ if (lhsType != EHeaderNormal && (lhsType == rhsType))
+ {
+ // They are both special headers of the same type
+ // Everything matches
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+TBool TEquivSip::IsQueryListCompatible(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const
+
+ {
+ TPtrC8 lhsSegment;
+ TPtrC8 rhsSegment;
+
+ TBool found = EFalse;
+ // roll back to the start of the lhs segment parser
+ aLhsParser.Reset();
+
+ while( aLhsParser.GetNext(lhsSegment) == KErrNone )
+ {
+ // roll back to the start of the rhs segment parser
+ aRhsParser.Reset();
+
+ found = EFalse;
+
+ while( aRhsParser.GetNext(rhsSegment) == KErrNone )
+ {
+ if (IsMatchHeader(lhsSegment, rhsSegment))
+ {
+ // a match has been found for this header so move to the next
+ // header in the lhs list
+ found = ETrue;
+ break;
+ }
+ }
+ if (!found)
+ {
+ // no match has been found so the headers are not equvalent
+ return EFalse;
+ }
+ }
+
+ return ETrue;
+ }
+
+TBool TEquivSip::IsMatchQueryL() const
+ {
+ HBufC8* lhs = DecodedSegmentLC(iLhs, EUriQuery);
+ HBufC8* rhs = DecodedSegmentLC(iRhs, EUriQuery);
+
+ TDelimitedQueryParser8 lhsParser;
+ lhsParser.Parse(*lhs);
+ TDelimitedQueryParser8 rhsParser;
+ rhsParser.Parse(*rhs);
+
+ TBool result = EFalse;
+
+ // first check that the number of headers are the same in both lists.
+ TInt lhsLength = ListLength(lhsParser);
+ TInt rhsLength = ListLength(rhsParser);
+ if (lhsLength == rhsLength)
+ {
+ // Check each parameter in the lhs parameter list with those in
+ // the rhs parameter list. If at any point a parameter is incompatible
+ // we'll return false.
+ result = IsQueryListCompatible(lhsParser, rhsParser);
+ }
+
+ CleanupStack::PopAndDestroy(2);
+ return result;
+ }
+
+TBool TEquivSip::IsMatchFragmentL() const
+ {
+ // We don't care about the fragment for SIP URIs
+ return ETrue;
+ }