--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerprotocols/wapbase/wutil/URLBASE.cpp Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,1130 @@
+// Copyright (c) 2000-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:
+// Purpose: Definition of CUrl class - Url processor based on RFC2396.
+// CUrl encapsulates a url and provides access to its components. On creation, the contents of
+// the url is in unescaped mode - excluded characters (as defined by RFC2396) have not been coded into their
+// escape triples. Two NewL() functions are provided. The first takes any descriptor and encapsulates it into
+// the CUrl object, and leaves if the the url begins with a ':' (EWapErrCorruptUrl) or if the scheme is
+//
+//
+
+// corrupted (EWapErrCorruptScheme). The second NewL() creates a url with a file scheme (file://) from a
+// TParseBase argument, and will leave if the url is invalid (EWapErrCorruptUrl). Two static functions have
+// been provided that each take a descriptor argument which is then escape encoded/decoded.
+//
+// NOTE - maintainer needs detailed knowledge of url parsing (RFC2396)
+//
+
+// System includes
+//
+#include <Utf.h>
+
+// CUrl class signature
+//
+#include "urlbase.h"
+
+// Static data used in this class
+//
+const TInt KCUrlInvalidCharPos = -1;
+const TInt KUrlConversionBufferSize = 50;
+
+// Constants
+_LIT(KHexDigit, "0123456789ABCDEF");
+_LIT(KUnwiseData, "{}|\\^[]\'");
+_LIT(KDelimsData, "<>#%\"");
+_LIT(KReservedData, ";/?:@&=+$,");
+_LIT(KReservedDataForPath, ";?@&=+$,");
+
+// Delimiters and scheme identifiers for urls
+_LIT(KUrlPathDelimiter,"/");
+_LIT(KUrlFileSchemeSignature,"file://");
+_LIT(KUrlLoc,"//");
+_LIT(KUrlColon,":");
+_LIT(KUrlQMark,"?");
+_LIT(KUrlHash,"#");
+
+// Implementation of CUrl
+//
+
+EXPORT_C CUrl* CUrl::NewL(const TDesC& aUrl)
+//
+// Static factory c'tor.
+ {
+ CUrl* url = new(ELeave) CUrl();
+ CleanupStack::PushL(url);
+ url->ConstructL(aUrl);
+ CleanupStack::Pop();
+ return url;
+ }
+
+EXPORT_C CUrl* CUrl::NewL(const TParseBase& aFileName)
+//
+// Static factory c'tor. Used for creating CUrl object for a file on local file system
+ {
+ CUrl* url = new(ELeave) CUrl();
+ CleanupStack::PushL(url);
+ url->ConstructL(aFileName);
+ CleanupStack::Pop();
+ return url;
+ }
+
+CUrl::CUrl()
+//
+// Default c'tor
+ {
+ }
+
+EXPORT_C CUrl::~CUrl()
+//
+// D'tor
+ {
+ delete iUrlDes;
+ }
+
+void CUrl::ConstructL(const TDesC& aUrl)
+//
+// Non-trivial c'tor - can be used for all general urls
+ {
+ // Stripe any leading whitespace
+ TPtrC url = aUrl;
+ while( url.Locate(' ') == 0 )
+ {
+ // Remove the leading whitespace -> set pointer to second character
+ url.Set(url.Mid(1));
+ }
+ iUrlDes = url.AllocL();
+
+ // Check to see if there's ':' at start of aUrl
+ TInt colonPos = aUrl.Locate(':');
+ if (colonPos == 0)
+ User::Leave(EWapErrCorruptUrl);
+ TPtrC scheme(Component(EUrlScheme));
+ CheckSchemeValidL(scheme);
+ }
+
+void CUrl::CheckSchemeValidL(const TDesC& aScheme) const
+ { // Check the scheme, leave if corrupt
+ for (TInt i=0; i < aScheme.Length(); i++)
+ {
+ TChar c = aScheme[i];
+ TBool ok = (c>='a' && c<='z') || (c>='A' && c <='Z');
+
+ if (!ok && i > 0)
+ ok = (c>='0' && c<='9') || c == '+' || c == '-' || c == '.';
+
+ if (!ok)
+ User::Leave(EWapErrCorruptScheme);
+ }
+ }
+
+void CUrl::ConstructL(const TParseBase& aFileName)
+//
+// Non-trivial c'tor - used to create Urls for local file space only. NO scheme in aFileName
+ {
+ if( aFileName.IsWild() )
+ User::Leave(EWapErrCorruptUrl);
+
+ // Convert Unicode file name into UTF8 format
+ HBufC8* utf8 = ConvertFromUnicodeToUtf8L(aFileName.FullName());
+ CleanupStack::PushL(utf8);
+
+ // Convert to 16-bit format
+ HBufC* escapedFullPath = HBufC::NewLC(utf8->Length());
+ escapedFullPath->Des().Copy(*utf8);
+
+ // Need to escape encode all the components - start with filename, then path and last the drive
+ TPtr fullPath = escapedFullPath->Des();
+ if ( fullPath.Compare(KNullDesC) )
+ {
+ // Convert '\' to '/' then escape encode with EUrlPath - this doesn't encode '/' and ':'
+ for (TInt i=0; i<fullPath.Length(); ++i)
+ {
+ if (fullPath[i] == KPathDelimiter)
+ fullPath[i] = '/';
+ }
+ escapedFullPath = EscapeEncodeL(fullPath, EUrlPath);
+ CleanupStack::PopAndDestroy(); // escapedFullPath (old version)
+ CleanupStack::PushL(escapedFullPath); // new version
+
+ // Replace ':' with '|'
+ fullPath.Set(escapedFullPath->Des());
+ TInt colonPos = fullPath.Locate(KDriveDelimiter);
+ if( colonPos != KErrNotFound )
+ fullPath[colonPos] = '|';
+ }
+ // Form the url
+ TInt size = KUrlFileSchemeSignature().Length() + KUrlPathDelimiter().Length() + fullPath.Length();
+
+ iUrlDes = HBufC::NewL(size);
+ iUrlDes->Des().Append(KUrlFileSchemeSignature());
+ iUrlDes->Des().Append(KUrlPathDelimiter());
+ iUrlDes->Des().Append(fullPath);
+
+ CleanupStack::PopAndDestroy(2); // escapedFullPath, utf8
+ }
+
+EXPORT_C CUrl* CUrl::ResolveL(CUrl& aBaseUrl, CUrl& aRelativeUrl)
+//
+// Based on the relative parsing algorithm in RFC2396
+ {
+ // Return copy of aRelativeUrl if aBaseUrl is empty
+ if (aBaseUrl.UrlDes().Compare(KNullDesC)==0)
+ return aRelativeUrl.AllocL();
+
+ TPtrC relativeUrl(aRelativeUrl.UrlDes());
+
+ TPtrC relPath(aRelativeUrl.Component(EUrlPath));
+ TPtrC relAuth(aRelativeUrl.Component(EUrlAuthority));
+ TPtrC relScheme(aRelativeUrl.Component(EUrlScheme));
+ TPtrC relQuery(aRelativeUrl.Component(EUrlQuery));
+ TPtrC relFragment(aRelativeUrl.Component(EUrlFragment));
+
+ if (relScheme.Length() > 0)
+ {
+ // LOOPHOLE in RFC 1630 if schemes match then remove the scheme from the relative url
+ if (aBaseUrl.UrlDes().FindF(relScheme) == 0)
+ relativeUrl.Set(relativeUrl.Mid(relScheme.Length() + 1)); // remove the ':' as well
+ else // the relative url is absolute
+ return NewL(relativeUrl);
+ }
+
+ TBool useBaseAuth = ETrue;
+ TBool useRelQuery = ETrue;
+ TPtrC basePath(aBaseUrl.Component(EUrlPath));
+ HBufC* resolvedPath = NULL;
+ if (relPath.Compare(KNullDesC)==0 && relAuth.Compare(KNullDesC)==0
+ && relScheme.Compare(KNullDesC)==0 && relQuery.Compare(KNullDesC)==0) // relative URL could just be a fragment
+ {
+ // Use current document url (assume that it is aBaseUrl), including query, then add relative URL fragment
+ useRelQuery = EFalse;
+ resolvedPath = basePath.AllocLC();
+ }
+ else if (relativeUrl.Find(KUrlLoc) == 0) // relative url is a network path
+ {
+ // Set resolved path to be the relative path
+ useBaseAuth = EFalse;
+ resolvedPath = relPath.AllocLC();
+ }
+ else if (relPath.Locate('/') == 0) // relative url is an absolute path
+ {
+ resolvedPath = relPath.AllocLC();
+ }
+ else
+ {
+ // Do path resolution, merge the base path and relative path
+ if (relPath.Length() != 0)
+ // if the relative path is a query or fragment then shouldn't strip the document from the basePath
+ {
+ TInt endBasePath = basePath.LocateReverse('/');
+ if (endBasePath != KErrNotFound)
+ basePath.Set(basePath.Left(endBasePath + 1)); // keep the '/'
+ else
+ basePath.Set(_L("/")); // Create path of just '/'
+ }
+ // Resolve relative path against base path
+ resolvedPath = HBufC::NewLC(relPath.Length() + basePath.Length());
+ TRelativePaths relativePaths(basePath, relPath, resolvedPath->Des());
+ relativePaths.ResolveRelativePaths();
+ }
+
+ // put the url together
+ TPtrC baseScheme(aBaseUrl.Component(EUrlScheme));
+ TPtrC baseAuth(aBaseUrl.Component(EUrlAuthority));
+ TPtrC baseQuery(aBaseUrl.Component(EUrlQuery));
+
+ HBufC* resolvedUrl = HBufC::NewLC(aBaseUrl.UrlDes().Length()
+ + relativeUrl.Length()
+ + KUrlColon().Length()
+ + KUrlLoc().Length()
+ + KUrlQMark().Length()
+ + KUrlHash().Length()
+ + 1); // this will be long enough - extra 1 just in case basePath was empty
+ TPtr resolvedBuf = resolvedUrl->Des();
+
+ if (baseScheme.Length() > 0)
+ {
+ resolvedBuf.Append(baseScheme);
+ resolvedBuf.Append(KUrlColon);
+ }
+
+ resolvedBuf.Append(KUrlLoc);
+
+ if (useBaseAuth && baseAuth.Length() >0)
+ {
+ resolvedBuf.Append(baseAuth);
+ }
+ else if (relAuth.Length() > 0)
+ {
+ resolvedBuf.Append(relAuth);
+ }
+
+ resolvedBuf.Append(*resolvedPath);
+
+ if (useRelQuery && relQuery.Length() >0)
+ {
+ resolvedBuf.Append(KUrlQMark);
+ resolvedBuf.Append(relQuery);
+ }
+ else if (!useRelQuery && baseQuery.Length() >0)
+ {
+ resolvedBuf.Append(KUrlQMark);
+ resolvedBuf.Append(baseQuery);
+ }
+
+ if (relFragment.Length() >0)
+ {
+ resolvedBuf.Append(KUrlHash);
+ resolvedBuf.Append(relFragment);
+ }
+
+ CUrl * url = CUrl::NewL(*resolvedUrl);
+ CleanupStack::PopAndDestroy(2); // resolvedUrl, resolvedPath
+
+ return url;
+ }
+
+void CUrl::Panic(TPanicCode aPanicCode) const
+ {
+ _LIT(KWapCUrl,"Wap - CUrl");
+ User::Panic(KWapCUrl, aPanicCode);
+ }
+
+void CUrl::Part(TComponent aComponent, const TDesC& aUrl, TInt& aStartPos, TInt& aEndPos) const
+//
+// Takes a descriptor as a url and parses it for the start and end positions of a particular component.
+// KCUrlInvalidCharPos is used to indicate that component is not in url.
+//
+// Based on RFC2396
+ {
+ aStartPos = aEndPos = KCUrlInvalidCharPos;
+
+ TPtrC url = aUrl;
+ // search for first of ':' | '/' | '?' | '#'
+ TInt stripped =0;
+
+ TInt colonPos = aUrl.Locate(':');
+ __ASSERT_ALWAYS(colonPos != 0,Panic(EInvalidUrl)); // if ':' is first character then it is invalid
+ TInt hashPos = aUrl.Locate('#');
+ TInt slashPos = aUrl.Locate('/');
+ TInt queryPos = aUrl.Locate('?');
+
+ colonPos = colonPos == KErrNotFound ? KMaxTInt : colonPos;
+ hashPos = hashPos == KErrNotFound ? KMaxTInt : hashPos;
+ slashPos = slashPos == KErrNotFound ? KMaxTInt : slashPos;
+ queryPos = queryPos == KErrNotFound ? KMaxTInt : queryPos;
+
+ // if ':' is before others then there is a scheme so extract it
+ if (colonPos < hashPos && colonPos < slashPos && colonPos < queryPos)
+ {
+ if (aComponent == EUrlScheme)
+ {
+ aStartPos = stripped;
+ aEndPos = colonPos -1;
+ return;
+ }
+
+ if (url.Length() == colonPos + 1) // reached the end of the url
+ return;
+ url.Set(url.Mid(colonPos+1));
+ stripped += colonPos+1;
+ hashPos -= colonPos+1;
+ slashPos -= colonPos+1;
+ queryPos -= colonPos+1;
+ }
+
+ // if first 2 characters are '//' then a host exists,
+ if (url.Find(KUrlLoc) == 0)
+ {
+ TInt urlLocLength = KUrlLoc().Length();
+ if (url.Length() == urlLocLength) // reached the end of the url
+ return;
+ // extract '//' and rescan for '/'
+ url.Set(url.Mid(urlLocLength));
+ stripped += urlLocLength;
+ hashPos -= urlLocLength;
+ queryPos -= urlLocLength;
+ slashPos = url.Locate('/');
+ slashPos = slashPos == KErrNotFound ? KMaxTInt : slashPos;
+
+ // host is ended by first of '#' | '?' | '/' | end of url
+ TInt hostEndCharPos = slashPos;
+ hostEndCharPos = hashPos < hostEndCharPos ? hashPos : hostEndCharPos;
+ hostEndCharPos = queryPos < hostEndCharPos ? queryPos : hostEndCharPos;
+ hostEndCharPos = url.Length() < hostEndCharPos ? url.Length() : hostEndCharPos;
+
+ if (aComponent == EUrlAuthority)
+ {
+ aStartPos = stripped;
+ aEndPos = hostEndCharPos+stripped-1;
+ return;
+ }
+ if (aComponent == EUrlLocation ||
+ aComponent == EUrlUsername ||
+ aComponent == EUrlPassword)
+ {
+ aStartPos = stripped;
+ aEndPos = hostEndCharPos+stripped-1;
+ // We need part of the authority. Extract it
+ PartOfAuthority(aComponent, aUrl, aStartPos, aEndPos);
+ return;
+ }
+ // Have we reached the end of the url
+ if (url.Length() == hostEndCharPos)
+ return;
+ // extract host
+ url.Set(url.Mid(hostEndCharPos));
+ stripped += hostEndCharPos;
+ slashPos -= hostEndCharPos;
+ hashPos -= hostEndCharPos;
+ queryPos -= hostEndCharPos;
+ }
+
+ // If first character is '/' | this is the start of a relative url | there is no authority then path exists
+ // as long as it isn't just a query or fragment
+ if ((slashPos == 0 || stripped == 0 || stripped == colonPos +1 ) && hashPos != 0 && queryPos !=0)
+ {
+ TInt pathEndCharPos = queryPos;
+ pathEndCharPos = hashPos < pathEndCharPos ? hashPos : pathEndCharPos;
+ pathEndCharPos = url.Length() < pathEndCharPos ? url.Length() : pathEndCharPos;
+ if (aComponent == EUrlPath)
+ {
+ aStartPos = stripped;
+ aEndPos = pathEndCharPos+stripped-1;
+ return;
+ }
+ if (url.Length() == pathEndCharPos) // reached the end of the url
+ return;
+ // extractPath
+ url.Set(url.Mid(pathEndCharPos));
+ stripped += pathEndCharPos ;
+ queryPos -= pathEndCharPos ;
+ hashPos -= pathEndCharPos ;
+ }
+
+ // if first is '?' then query exists
+ if (queryPos == 0)
+ {
+ // extract ?, query is ended by '#' | end of url
+ if (url.Length() == 1) // reached the end of the url
+ return;
+ url.Set(url.Mid(1));
+ stripped += 1;
+ hashPos -= 1;
+ // extract query
+ TInt queryEndCharPos = hashPos;
+ queryEndCharPos = url.Length() < queryEndCharPos ? url.Length() : queryEndCharPos;
+ if (aComponent == EUrlQuery)
+ {
+ aStartPos = stripped;
+ aEndPos = queryEndCharPos+stripped-1;
+ return;
+ }
+ if (url.Length() == queryEndCharPos) // reached the end of the url
+ return;
+ url.Set(url.Mid(queryEndCharPos));
+ stripped += queryEndCharPos;
+ hashPos -= queryEndCharPos;
+ }
+
+ if (hashPos == 0)
+ {
+ if (url.Length() == 1) // reached the end of the url
+ return;
+ // extract hash
+ url.Set(url.Mid(1));
+ stripped += 1;
+ // fragment left
+ if (aComponent == EUrlFragment)
+ {
+ aStartPos = stripped;
+ aEndPos = stripped + url.Length() -1;
+ return;
+ }
+ }
+ __ASSERT_DEBUG( aStartPos == aEndPos && aEndPos == KCUrlInvalidCharPos, Panic(EInvalidUrl));
+ }
+
+void CUrl::PartOfAuthority(TComponent aComponent, const TDesC& aUrl, TInt& aStartPos, TInt& aEndPos) const
+ {
+ if (aEndPos < aStartPos)
+ {
+ // We don't have what the user asked for
+ aStartPos = KCUrlInvalidCharPos;
+ aEndPos = KCUrlInvalidCharPos;
+ return;
+ }
+
+ TPtrC authority = aUrl.Mid(aStartPos, aEndPos - aStartPos);
+ TInt endPos = aEndPos - aStartPos;
+ TInt colonPos = authority.Locate(':');
+ TInt atPos = authority.Locate('@');
+ if (atPos == KErrNotFound)
+ {
+ // There isn't a username or password.
+ if (aComponent != EUrlLocation)
+ {
+ // We don't have what the user asked for
+ aStartPos = KCUrlInvalidCharPos;
+ aEndPos = KCUrlInvalidCharPos;
+ }
+ // Else all we've got is the location, so we can return
+ // without doing anything
+ return;
+ }
+
+ // We have an @.
+ if (aComponent == EUrlLocation)
+ {
+ if (atPos != endPos - 1)
+ {
+ // We have a location of non-zero length
+ aStartPos += atPos + 1;
+ return;
+ }
+ else
+ {
+ aStartPos = KCUrlInvalidCharPos;
+ aEndPos = KCUrlInvalidCharPos;
+ }
+ }
+ else
+ {
+ // Either username or password
+ if (aComponent == EUrlUsername)
+ {
+ if (colonPos == KErrNotFound || colonPos > atPos)
+ {
+ // No password
+ aEndPos = aStartPos + atPos - 1;
+ return;
+ }
+ else
+ {
+ aEndPos = aStartPos + colonPos - 1;
+ return;
+ }
+ }
+ else
+ {
+ // They want the password
+ if (colonPos == KErrNotFound || colonPos > atPos)
+ {
+ // There isn't a password
+ aStartPos = KCUrlInvalidCharPos;
+ aEndPos = KCUrlInvalidCharPos;
+ }
+ else
+ {
+ aEndPos = aStartPos + atPos - 1;
+ aStartPos += colonPos + 1;
+ }
+ }
+ }
+ }
+
+EXPORT_C const TPtrC CUrl::Component(TComponent aType) const
+ {
+ TInt start = KCUrlInvalidCharPos;
+ TInt end = KCUrlInvalidCharPos;
+
+ TComponent type(aType);
+ if (aType == EUrlFileName)
+ type = EUrlPath;
+
+
+ Part(type, *iUrlDes, start,end);
+ if (start == KCUrlInvalidCharPos || end == KCUrlInvalidCharPos)
+ return KNullDesC();
+
+ TInt length = end - start +1;
+ if (end == (*iUrlDes).Length())
+ length--;
+
+ TPtrC component((*iUrlDes).Mid(start, length));
+
+ if (aType == EUrlFileName)
+ {
+ TInt slashPos = component.LocateReverse('/');
+ if (slashPos == KErrNotFound)
+ return KNullDesC();
+ else
+ component.Set(component.Right(component.Length() - (slashPos +1)));
+ }
+
+ return component;
+ }
+
+
+EXPORT_C void CUrl::SetComponentL(TComponent aComponent, const TDesC& aValue)
+ {
+ TInt start, end;
+ // As a crude first step, we always resize the URL descriptor to
+ // be longer than it currently is by 4 characters longer than the
+ // value. Then at the end, we'll resize it to be the right length.
+ // 4 allows :// to be inserted if a scheme is set when none is present
+ iUrlDes=iUrlDes->ReAllocL(iUrlDes->Length() + aValue.Length() + 4);
+
+ Part(aComponent, *iUrlDes, start, end);
+
+ if (aComponent == EUrlScheme && start == KCUrlInvalidCharPos && end == KCUrlInvalidCharPos)
+ { // We're trying to add a scheme, but there isn't one already. Check if scheme valid
+ // There could already be a // at the start, but there can't be a : at the start
+ CheckSchemeValidL(aValue);
+ // insert location if required
+ TPtr wptr(iUrlDes->Des());
+ // insert // at the start
+ if(wptr.Find(KUrlLoc)!=0)
+ wptr.Insert(0,KUrlLoc);
+ // insert scheme and a colon
+ wptr.Insert(0,KUrlColon);
+ wptr.Insert(0,aValue);
+ }
+ else if ((aComponent == EUrlUsername || aComponent == EUrlPassword) &&
+ (start == KCUrlInvalidCharPos || end == KCUrlInvalidCharPos))
+ {
+ // We're trying to add a username or password, but there isn't
+ // one already, so the surrounding punctuation won't be there.
+ if (aComponent == EUrlUsername)
+ {
+ Part(EUrlAuthority, *iUrlDes, start, end);
+ // If there isn't an authority, this is too complex.
+ if (start == KCUrlInvalidCharPos)
+ User::Leave(KErrNotSupported);
+
+ // We've now found the correct start position. Check if
+ // the password exists
+ TInt scratch;
+ Part(EUrlPassword, *iUrlDes, end, scratch);
+ if (end == KCUrlInvalidCharPos)
+ {
+ // No username or password. This means we need to add the @
+ iUrlDes->Des().Insert(start, _L("@"));
+ end = start;
+ }
+ else
+ {
+ // There is a password, so end currently points after
+ // the colon.
+ end--;
+ }
+ }
+ else
+ {
+ // aComponent == EUrlPassword
+ TInt scratch;
+ Part(EUrlUsername, *iUrlDes, scratch, start);
+ if (start == KCUrlInvalidCharPos)
+ {
+ // No username. We need to find the start of the
+ // location, and add :@ after it and insert the
+ // password between them.
+
+
+ Part(EUrlLocation, *iUrlDes, start, scratch);
+ iUrlDes->Des().Insert(start, _L(":@"));
+ }
+ else
+ {
+ // There is a username but no password. Add a colon at
+ // the end of it and then add the password afterwards.
+ iUrlDes->Des().Insert(++start, KUrlColon);
+ }
+ start++;
+ end = start;
+ }
+ }
+ else if (start == KCUrlInvalidCharPos || end == KCUrlInvalidCharPos)
+ {
+ // A complex case we can't deal with
+ User::Leave(KErrNotSupported);
+ }
+ else
+ {
+ // The easy case; end currently points at the last character;
+ // we want it to point one after.
+ end++;
+ }
+ if (start != KCUrlInvalidCharPos && end != KCUrlInvalidCharPos)
+ { // this check is necessary to catch the case where
+ // we set a scheme and there wasn't one already
+ iUrlDes->Des().Replace(start, end - start, aValue);
+ }
+ iUrlDes=iUrlDes->ReAllocL(iUrlDes->Length());
+ }
+
+EXPORT_C TBool CUrl::operator==(CUrl& aUrl) const
+ {
+ return !Compare(aUrl,EUrlGenericCompare);
+ }
+
+EXPORT_C TInt CUrl::Compare(CUrl& aUrl, TInt aCompareComps) const
+//
+// Scheme is case insensitive, rest of url is case sensitive
+ {
+ TInt result =0;
+ if (aCompareComps & EUrlScheme)
+ {
+ result += Component(EUrlScheme).CompareF(aUrl.Component(EUrlScheme));
+ if (result !=0)
+ return result;
+ }
+
+ if (aCompareComps & EUrlLocation)
+ {
+ result += Component(EUrlLocation).Compare(aUrl.Component(EUrlLocation));
+ if (result !=0)
+ return result;
+ }
+
+ if (aCompareComps & EUrlUsername)
+ {
+ result += Component(EUrlUsername).Compare(aUrl.Component(EUrlUsername));
+ if (result !=0)
+ return result;
+ }
+
+ if (aCompareComps & EUrlPassword)
+ {
+ result += Component(EUrlPassword).Compare(aUrl.Component(EUrlPassword));
+ if (result !=0)
+ return result;
+ }
+
+ if (aCompareComps & EUrlPath)
+ {
+ result += Component(EUrlPath).Compare(aUrl.Component(EUrlPath));
+ if (result !=0)
+ return result;
+ }
+
+ if (aCompareComps & EUrlQuery)
+ {
+ result += Component(EUrlQuery).Compare(aUrl.Component(EUrlQuery));
+ if (result !=0)
+ return result;
+ }
+
+ if (aCompareComps & EUrlFragment)
+ {
+ result += Component(EUrlFragment).Compare(aUrl.Component(EUrlFragment));
+ if (result !=0)
+ return result;
+ }
+ return result;
+ }
+
+EXPORT_C void CUrl::SetL(CUrl& aUrl)
+ {
+ HBufC* url = aUrl.UrlDes().AllocL();
+ delete iUrlDes;
+ iUrlDes = url;
+ }
+
+EXPORT_C CUrl* CUrl::AllocL() const
+ {
+ return CUrl::NewL(*iUrlDes);
+ }
+
+EXPORT_C CUrl* CUrl::AllocL(TComponent aComponent) const
+ {
+ if (aComponent == EUrlGenericCompare)
+ return AllocL();
+ else if (aComponent == EUrlNoCredentials)
+ {
+ TInt usernameStart;
+ TInt locationStart;
+ TInt scratch;
+ Part(EUrlUsername, *iUrlDes, usernameStart, scratch);
+ Part(EUrlLocation, *iUrlDes, locationStart, scratch);
+ // If there isn't a location and a username, we can just
+ // return the current URL.
+ if (locationStart == KCUrlInvalidCharPos ||
+ usernameStart == KCUrlInvalidCharPos)
+ return AllocL();
+ // Make a CUrl of the right length and then copy the correct
+ // data into it.
+ TInt lengthOfReturnedUrl = iUrlDes->Length() - locationStart +
+ usernameStart;
+ CUrl* result = CUrl::NewL(iUrlDes->Left(lengthOfReturnedUrl));
+ result->iUrlDes->Des().Replace(usernameStart,
+ lengthOfReturnedUrl - usernameStart,
+ iUrlDes->Right(lengthOfReturnedUrl -
+ usernameStart));
+ return result;
+ }
+ else return CUrl::NewL(Component(aComponent));
+ }
+
+EXPORT_C CUrl* CUrl::UrlEscapedL() const
+//
+// Create and return an escaped version of the current unescaped url
+ {
+ User::Panic(_L("Function Not Used"), KErrNotSupported);
+ return NULL;
+ }
+
+EXPORT_C CUrl* CUrl::UrlUnescapedL() const
+//
+// Create and return an unescaper version of the current escaped url
+ {
+ User::Panic(_L("Function Not Used"), KErrNotSupported);
+ return NULL;
+ }
+
+EXPORT_C HBufC* CUrl::EscapeEncodeL(const TDesC& aString)
+//
+// Deprecated function - should use overload function.
+ {
+ return EscapeEncodeL(aString, EUrlGenericCompare);
+ }
+
+EXPORT_C HBufC* CUrl::EscapeEncodeL(const TDesC& aString, TInt aEscapeMode)
+//
+// Encodes any excluded characters in aString as escape triples - excluded characters set by aEscapeMode
+ {
+ // Need to create an HBufC with our excluded characters
+ HBufC* excludedBuf = NULL;
+
+ switch (aEscapeMode)
+ {
+ case EUrlGenericCompare:
+ {
+ // This is normal operation - escape all sets of data other than KReservedData
+ excludedBuf = HBufC::NewLC(KUnwiseData().Length() + KDelimsData().Length());
+ TPtr excluded = excludedBuf->Des();
+ excluded.Append(KUnwiseData);
+ excluded.Append(KDelimsData);
+ } break;
+ case EUrlScheme:
+ {
+ // Escaping data in scheme - reserved chars have no special meaning so escape as well.
+ excludedBuf = HBufC::NewLC(KUnwiseData().Length() + KDelimsData().Length() + KReservedData().Length());
+ TPtr excluded = excludedBuf->Des();
+ excluded.Append(KUnwiseData);
+ excluded.Append(KDelimsData);
+ excluded.Append(KReservedData);
+ } break;
+ case EUrlPath:
+ {
+ // Escaping data in a local file path - same as EUrlScheme but don't escape '/' and ':'
+ excludedBuf = HBufC::NewLC(KUnwiseData().Length() + KDelimsData().Length() + KReservedDataForPath().Length());
+ TPtr excluded = excludedBuf->Des();
+ excluded.Append(KUnwiseData);
+ excluded.Append(KDelimsData);
+ excluded.Append(KReservedDataForPath);
+ } break;
+ default:
+ // Not supported return NULL
+ return NULL;
+ break;
+ }
+
+ // Descriptor to hex digits
+ const TDesC& HexDigit = KHexDigit;
+
+ // Allocate space to build escaped url - consider worse case, where all characters are excluded => length x 3
+ HBufC* buf = HBufC::NewLC(aString.Length()*3); // CS
+ TPtr escapedBuf = buf->Des();
+
+ for (TInt i=0; i<aString.Length(); ++i)
+ {
+ // Check if current character must be escaped, will leave if non 8-bit character
+ TChar currentChar = aString[i];
+ if (currentChar > 0xff)
+ User::Leave(EWapErrCorruptUrl);
+ // Check if aChar is a member of DelimsData or UnwiseData or a control character
+ if (excludedBuf->Locate(currentChar)!=KErrNotFound || (currentChar>=0x00 && currentChar<=0x1F) || currentChar==' ' || currentChar > 0x7E )
+ {
+ // Escaped character will be 8-bit
+ escapedBuf.Append('%');
+ TInt msNibble = (currentChar & 0xf0) >> 4; // Get msNibble by masking against 11110000 and dividing by 16 (>>4)
+ escapedBuf.Append(HexDigit[msNibble]);
+ TInt lsNibble = (currentChar & 0x0f); // Get lsNibble by masking against 00001111
+ escapedBuf.Append(HexDigit[lsNibble]);
+ }
+ else
+ {
+ escapedBuf.Append(currentChar);
+ }
+ }
+ // Create new HBufC object
+ HBufC* encodedString = escapedBuf.AllocL();
+
+ CleanupStack::PopAndDestroy(2); // buf, excludedBuf
+ return encodedString;
+ }
+
+EXPORT_C HBufC* CUrl::EscapeDecodeL(const TDesC& aString)
+//
+// Decodes any escape triples in aString back into excluded characters
+ {
+ // Descriptor to hex digits
+ const TDesC& HexDigit = KHexDigit;
+
+ // Allocate space for to build unescaped url
+ HBufC* buf = HBufC::NewLC(aString.Length()); // CS
+ TPtr unescapedBuf = buf->Des();
+
+ // Go through url
+ for (TInt i=0; i<aString.Length(); ++i)
+ {
+ // See if at start of an escape triple
+ TChar currentChar = aString[i];
+ if (currentChar == '%')
+ {
+ // Check that next two characters are valid
+ TChar msNibble = aString[i+1];
+ if (msNibble.IsAlpha())
+ msNibble.UpperCase();
+ TChar lsNibble = aString[i+2];
+ if (lsNibble.IsAlpha())
+ lsNibble.UpperCase();
+ TInt msNibbleValue = HexDigit.Locate(msNibble);
+ TInt lsNibbleValue = HexDigit.Locate(lsNibble);
+ if (msNibbleValue == KErrNotFound || lsNibbleValue == KErrNotFound)
+ {
+ User::Leave(EWapErrCorruptUrl);
+ }
+ else
+ {
+ // Convert characters into hex value
+ TInt hex = 0x10*msNibbleValue + 0x01*lsNibbleValue;
+ unescapedBuf.Append(hex);
+ }
+ // Move index to get next character
+ i+=2;
+ }
+ else
+ {
+ unescapedBuf.Append(currentChar);
+ }
+ }
+ // Create new HBufC object
+ HBufC* encodedString = unescapedBuf.AllocL();
+
+ CleanupStack::PopAndDestroy(); // buf
+ return encodedString;
+ }
+
+EXPORT_C HBufC8* CUrl::ConvertFromUnicodeToUtf8L(const TDesC& aString)
+//
+// Converts input string from unicode to UTF8 format - converted string is returned in 8-bit format
+ {
+ // Return an empty buffer straight-away
+ if( aString.Compare(KNullDesC) == 0 )
+ return KNullDesC8().AllocL();
+
+ // Convert from Unicode to UTF8
+ TPtrC unicode = aString;
+ TBuf8<KUrlConversionBufferSize> buf;
+ HBufC8* utf8Buffer = HBufC8::NewLC(unicode.Length());
+ TPtr8 utf8 = utf8Buffer->Des();
+
+ // Loop until all of the filename is converted
+ FOREVER
+ {
+ const TInt returnValue = CnvUtfConverter::ConvertFromUnicodeToUtf8(buf, unicode);
+ if( returnValue == CnvUtfConverter::EErrorIllFormedInput || returnValue < 0)
+ User::Leave(EWapErrCorruptUrl);
+
+ // Is escapedFullPath too small?
+ if( utf8.Length() + buf.Length() > utf8.MaxLength() )
+ {
+ utf8Buffer = utf8Buffer->ReAllocL(utf8.Length() + buf.Length());
+ CleanupStack::Pop(); // utf8Buffer (old version)
+ CleanupStack::PushL(utf8Buffer); // new version
+ utf8.Set(utf8Buffer->Des());
+ }
+ // Copy converted characters
+ utf8.Append(buf);
+
+ if( returnValue==0 )
+ break; // All of aUnicodeText has been converted and handled
+
+ // Set input descriptor to remaining characters
+ unicode.Set(unicode.Right(returnValue));
+ }
+ CleanupStack::Pop(); // utf8Buffer
+ return utf8Buffer; // Ownership transfered to caller
+ }
+
+EXPORT_C HBufC* CUrl::ConvertToUnicodeFromUtf8L(const TDesC8& aString)
+//
+// Converts input string from UTF8 to Unicode format - converted string is returned in 16-bit format
+ {
+ // Return an empty buffer straight-away
+ if( aString.Compare(KNullDesC8) == 0 )
+ return KNullDesC().AllocL();
+
+ // Convert from Unicode to UTF8
+ TPtrC8 utf8 = aString;
+ TBuf<KUrlConversionBufferSize> buf;
+ HBufC* unicodeBuffer = HBufC::NewLC(utf8.Length());
+ TPtr unicode = unicodeBuffer->Des();
+
+ // Loop until all of the filename is converted
+ FOREVER
+ {
+ const TInt returnValue = CnvUtfConverter::ConvertToUnicodeFromUtf8(buf, utf8);
+ if( returnValue == CnvUtfConverter::EErrorIllFormedInput || returnValue < 0)
+ User::Leave(EWapErrCorruptUrl);
+
+ // Is escapedFullPath too small?
+ if( unicode.Length() + buf.Length() > unicode.MaxLength() )
+ {
+ unicodeBuffer = unicodeBuffer->ReAllocL(unicode.Length() + buf.Length());
+ CleanupStack::Pop(); // unicodeBuffer (old version)
+ CleanupStack::PushL(unicodeBuffer); // new version
+ unicode.Set(unicodeBuffer->Des());
+ }
+ // Copy converted characters
+ unicode.Append(buf);
+
+ if( returnValue==0 )
+ break; // All of utf8 has been converted and handled
+
+ // Set input descriptor to remaining characters
+ utf8.Set(utf8.Right(returnValue));
+ }
+ CleanupStack::Pop(); // unicodeBuffer
+ return unicodeBuffer; // Ownership transfered to caller
+ }
+
+//
+// TRelativePaths
+//
+CUrl::TRelativePaths::TRelativePaths(TPtrC aBasePath, TPtrC aRelativePath, TPtr aResolvedPath)
+ : iBasePath(aBasePath), iRelativePath(aRelativePath), iResolvedPath(aResolvedPath)
+//
+// Trivial c'tor
+ {
+ }
+
+void CUrl::TRelativePaths::ResolveRelativePaths()
+//
+// Resolves iRelativePath against iBasePath, algorithm based on RFC2396 - result in iResolvedPath
+ {
+ TBool finished = EFalse;
+ while (!finished && iRelativePath.Length()>0)
+ {
+ // This applies only in cases such as '..\etc'
+ if (iRelativePath.Locate('/')==0)
+ iRelativePath.Set(iRelativePath.Mid(1));
+ TInt relPathLength = iRelativePath.Length();
+ if (relPathLength>0 && iRelativePath[0] == '.')
+ {
+ // Case 1 - .<end> -> remove '.'
+ if (relPathLength == 1)
+ {
+ iRelativePath.Set(KNullDesC);
+ finished = ETrue;
+ }
+ // Length of iRelative MUST be > 1, otherwise would not have got here
+ // Case 2 - ./ -> remove './' and continue
+ else if (iRelativePath[1] == '/')
+ {
+ iRelativePath.Set(iRelativePath.Mid(2));
+ }
+ // Case 3 & 4 - ..<end> or ../ -> remove a path from iBasePath
+ else if (iRelativePath[1] == '.')
+ {
+ if (relPathLength == 2 || (relPathLength>2 && iRelativePath[2] == '/'))
+ {
+ // Try to remove a directory from iBasePath
+ TInt basePathLength = iBasePath.Length();
+ // If base path empty or just '/' -> finish
+ if (basePathLength==0 || (basePathLength==1 && iBasePath[0] == '/'))
+ {
+ finished = ETrue;
+ }
+ else
+ {
+ TInt endBasePath = iBasePath.LocateReverse('/');
+ if (endBasePath == basePathLength - 1)
+ {
+ // Have found / on end of path - remove and rescan for '/'
+ iBasePath.Set(iBasePath.Left(endBasePath));
+ endBasePath = iBasePath.LocateReverse('/');
+ }
+ if (endBasePath > KErrNotFound)
+ {
+ // Remove a directory, keeping the end '/'
+ iBasePath.Set(iBasePath.Left(endBasePath+1));
+ iRelativePath.Set(iRelativePath.Mid(2)); // Remove .. at start
+ }
+ }
+ }
+ else
+ {
+ // iRelative now of form '..etc'
+ finished = ETrue;
+ }
+ }
+ else
+ {
+ // iRelative now of form '.etc'
+ finished = ETrue;
+ }
+ }
+ else
+ {
+ // iRelativePath now of form 'etc'
+ finished = ETrue;
+ }
+ } // while (!finished && iRelativePath.Length>0)
+ // Form the resolved path
+ iResolvedPath.Append(iBasePath);
+ iResolvedPath.Append(iRelativePath);
+ CleanResolvedPath();
+ }
+
+void CUrl::TRelativePaths::CleanResolvedPath()
+//
+// Deal with any /. and /../ in iResolvedPath - produced if the relative url is of the form g/./h or g/../h
+ {
+ TInt pos = 0;
+ // Deal with /../ by locating the previous / and removing everything between
+ // Eg /data/.../stuff -> /stuff
+ while (pos > KErrNotFound)
+ {
+ _LIT(KSlashDotDotSlash,"/../");
+ pos = iResolvedPath.Find(KSlashDotDotSlash);
+ if (pos > KErrNotFound)
+ {
+ TPtrC leftHandSide(iResolvedPath.Left(pos));
+ TInt slashPos = leftHandSide.LocateReverse('/');
+ if (slashPos > KErrNotFound)
+ iResolvedPath.Delete(slashPos, pos - slashPos +3);
+ else
+ pos = KErrNotFound;
+ }
+ }
+ // Remove any /. in iResolvedPath
+ pos = 0;
+ while (pos > KErrNotFound)
+ {
+ _LIT(KSlashDot,"/.");
+ pos = iResolvedPath.Find(KSlashDot);
+ TInt resolvedLength = iResolvedPath.Length();
+ if (pos > KErrNotFound)
+ {
+ if (resolvedLength == pos+2) // just remove the .
+ iResolvedPath.Delete(pos+1,1);
+ else if (resolvedLength > pos +1 && iResolvedPath[pos+2] == '/') // is of the form /./
+ iResolvedPath.Delete(pos,2);
+ else
+ pos = KErrNotFound;
+ }
+ }
+ }