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: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include "UriUtilsInternal.h" sl@0: #include "TUriCInternal.h" sl@0: #include "CUriInternal.h" sl@0: sl@0: // Panic category sl@0: // sl@0: #ifdef _DEBUG sl@0: _LIT(KUriPanicCategory,"URI-CURI"); sl@0: #endif sl@0: sl@0: // Constants sl@0: // sl@0: _LIT(KFileUriPanicCategory,"FILEURI-CURI"); sl@0: sl@0: sl@0: sl@0: sl@0: // sl@0: // sl@0: // Implementation of CUri8 sl@0: // sl@0: // sl@0: sl@0: /** sl@0: Static factory constructor. Uses two phase construction and leaves nothing on the sl@0: CleanupStack. Creates a uri object which is a copy of the input parameter aUri. sl@0: sl@0: @since 6.0 sl@0: @param aUri A reference to a parsed uri object. sl@0: @return A pointer to the newly created CUri8 object. sl@0: @post A fully constructed and initialized CUri8 object. sl@0: */ sl@0: EXPORT_C CUri8* CUri8::NewL(const TUriC8& aUri) sl@0: { sl@0: CUri8* self = CUri8::NewLC(aUri); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Static factory constructor. Uses two phase construction and leaves a pointer to sl@0: created object on the CleanupStack. Creates a uri object which is a copy of the sl@0: input parameter aUri. sl@0: sl@0: @since 6.0 sl@0: @param aUri A reference to a parsed uri object. sl@0: @return A pointer to the newly created CUri8 object. sl@0: @post A fully constructed and initialized CUri8 object. sl@0: */ sl@0: EXPORT_C CUri8* CUri8::NewLC(const TUriC8& aUri) sl@0: { sl@0: CUri8* self = new (ELeave) CUri8(aUri); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Static factory constructor. Uses two phase construction and leaves nothing on the sl@0: CleanupStack. Creates a uri object which is empty. sl@0: sl@0: @since 6.0 sl@0: @return A pointer to the newly created CUri8 object. sl@0: @post A fully constructed and initialized CUri8 object. sl@0: */ sl@0: EXPORT_C CUri8* CUri8::NewL() sl@0: { sl@0: CUri8* self = CUri8::NewLC(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Static factory constructor. Uses two phase construction and leaves a pointer to created sl@0: object on the CleanupStack. Creates a uri object which is empty. sl@0: sl@0: @since 6.0 sl@0: @return A pointer to the newly created CUri8 object. sl@0: @post A fully constructed and initialized CUri8 object. sl@0: */ sl@0: EXPORT_C CUri8* CUri8::NewLC() sl@0: { sl@0: CUri8* self = new (ELeave) CUri8(TUriC8()); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Static factory constructor. This creates a CUri8 object that is an absolute uri resulting sl@0: from a reference uri being resolved against a base uri. sl@0: sl@0: @warning Ownership of created CUri8 object is transferred to the caller. sl@0: @leave KUriErrBadBasePath if the base path is not an absolute path and not empty. sl@0: @since 6.0 sl@0: @param aBaseUri A referece to the parsed base uri. sl@0: @param aRefUri A referece to the parsed reference uri. sl@0: @return A pointer to the newly created CUri8 object. sl@0: @pre The base uri must have an absolute or empty path, otherwise will leave sl@0: with KUriErrBadBasePath. sl@0: @post A fully constructed and initialized CUri8 object. sl@0: */ sl@0: EXPORT_C CUri8* CUri8::ResolveL(const TUriC8& aBaseUri, const TUriC8& aRefUri) sl@0: { sl@0: // Check for a base Uri sl@0: if( aBaseUri.UriDes().Compare(KNullDesC8) == 0 ) sl@0: { sl@0: // Empty base Uri - resolved Uri is the reference Uri sl@0: return NewL(aRefUri); sl@0: } sl@0: // See if ref has scheme and it is the same as base Uri sl@0: if( aRefUri.IsPresent(EUriScheme) && (aRefUri.Compare(aBaseUri, EUriScheme) != 0) ) sl@0: { sl@0: // Ref has a scheme different to base Uri's - it is an absolute Uri sl@0: return NewL(aRefUri); sl@0: } sl@0: // Check for presence of components sl@0: TBool useBaseQuery = EFalse; sl@0: HBufC8* resolvedPath = FormResolvedPathLC(aBaseUri, aRefUri, useBaseQuery); sl@0: sl@0: //Removes dot segemnts in Resolved uri as specified in RFC3986 section 5.2. sl@0: RemoveExtraneousDotSegmentsL(resolvedPath); sl@0: sl@0: // Put the Uri together sl@0: TUriC8 uri; sl@0: FormResolvedUri(uri.iComponent, aBaseUri, aRefUri, resolvedPath, useBaseQuery); sl@0: sl@0: // Create the resolved Uri and cleanup sl@0: CUri8* resolvedUri = NewL(uri); sl@0: CleanupStack::PopAndDestroy(resolvedPath); sl@0: sl@0: return resolvedUri; sl@0: } sl@0: sl@0: /** sl@0: Destructor. sl@0: sl@0: @since 6.0 sl@0: */ sl@0: EXPORT_C CUri8::~CUri8() sl@0: { sl@0: delete iUriBuf; sl@0: } sl@0: sl@0: /** sl@0: Provides a reference to the parsed uri. Allows access to the non-modifying API for TUriC8. sl@0: sl@0: @since 6.0 sl@0: @return A const reference to the parsed uri object. sl@0: */ sl@0: EXPORT_C const TUriC8& CUri8::Uri() const sl@0: { sl@0: return iUri; sl@0: } sl@0: sl@0: /** sl@0: Intended Usage : Sets the specified component in the uri. The component is set to the value sl@0: given in the argument aData. If the specified component already exists then it is replaced sl@0: with the new value. sl@0: sl@0: @warning The userinfo and port components can only be set if the host component sl@0: is present. Setting these components without a host component present will have no sl@0: effect on the uri. sl@0: @since 6.0 sl@0: @param aData A descriptor pointer to the new value for the uri component. sl@0: @param aComponent An enum specifying the component to be set. sl@0: @pre Object is fully constructed. sl@0: @post The uri has the specified component set to the new value. sl@0: @Leave KErrArgument If aComponent goes out of range. sl@0: */ sl@0: EXPORT_C void CUri8::SetComponentL(const TDesC8& aData, TUriComponent aComponent) sl@0: { sl@0: // Update the appropriate component table entry sl@0: iUri.iComponent[aComponent].Set(aData); sl@0: sl@0: // Copy to the buffer by forming the uri sl@0: FormUriL(); sl@0: } sl@0: sl@0: /** sl@0: Removes the specified component from the uri. If the component does not exist then this function sl@0: does nothing. sl@0: sl@0: @warning If host is removed, then userinfo and port components will also sl@0: be removed. sl@0: @since 6.0 sl@0: @param aComponent An enum specifying the component to be removed. sl@0: @pre Object is fully constructed. sl@0: @post The uri is updated to exclude the specified component. sl@0: */ sl@0: EXPORT_C void CUri8::RemoveComponentL(TUriComponent aComponent) sl@0: { sl@0: if( iUri.IsPresent(aComponent) ) sl@0: { sl@0: // Remove the component - set pointer to NULL and length to zero sl@0: iUri.iComponent[aComponent].Set(NULL,0); sl@0: sl@0: // Re-form buffer and component table sl@0: FormUriL(); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Constructor. First phase of two-phase construction method. Does non-allocating construction. sl@0: sl@0: @since 6.0 sl@0: @param aUri The parsed uri component information from which to create sl@0: the uri. sl@0: */ sl@0: CUri8::CUri8(const TUriC8& aUri) sl@0: : CBase(), iUri(aUri) sl@0: { sl@0: } sl@0: sl@0: /** sl@0: Second phase of two-phase construction method. Does any allocations required to fully construct sl@0: the object. sl@0: sl@0: @since 6.0 sl@0: @pre First phase of construction is complete. sl@0: @post The object is fully constructed and initialized. sl@0: */ sl@0: void CUri8::ConstructL() sl@0: { sl@0: // Create the HBufC sl@0: FormUriL(); sl@0: } sl@0: sl@0: /** sl@0: Forms the uri from the parsed uri information. A copy of the parsed uri is created. The parsed uri sl@0: is changed to refer to the copy. sl@0: sl@0: @since 6.0 sl@0: @pre The parsed uri information is set. sl@0: @post The uri buffer is updated with the parsed uri information. sl@0: */ sl@0: void CUri8::FormUriL() sl@0: { sl@0: TBool isIPv6Host; sl@0: sl@0: // Calculate length of of the Uri sl@0: TInt length = CalculateUriLength(iUri.iComponent, isIPv6Host); sl@0: sl@0: // Create a temporary buffer and descriptor pointer to it sl@0: HBufC8* buf = HBufC8::NewL(length); sl@0: TPtr8 uri = buf->Des(); sl@0: sl@0: // Create the uri, updating the internal uri object sl@0: DoFormUri(uri, iUri.iComponent, isIPv6Host); sl@0: sl@0: // Update the internal buffer and descriptor pointer sl@0: delete iUriBuf; sl@0: iUriBuf = buf; sl@0: iUri.iUriDes.Set(iUriBuf->Des()); sl@0: } sl@0: sl@0: // sl@0: // sl@0: // Implementation of CUri16 sl@0: // sl@0: // sl@0: sl@0: /** sl@0: Static factory constructor. Uses two phase construction and leaves nothing on the CleanupStack. sl@0: Creates a uri object which is a copy of the input parameter aUri. sl@0: sl@0: @deprecated Deprecated in 9.1 sl@0: @since 6.0 sl@0: @param aUri A reference to a parsed uri object. sl@0: @return A pointer to the newly created CUri16 object. sl@0: @post A fully constructed and initialized CUri16 object. sl@0: */ sl@0: EXPORT_C CUri16* CUri16::NewL(const TUriC16& aUri) sl@0: { sl@0: CUri16* self = CUri16::NewLC(aUri); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Static factory constructor. Uses two phase construction and leaves a pointer to created object on sl@0: the CleanupStack. Creates a uri object which is a copy of the input parameter aUri. sl@0: sl@0: @since 6.0 sl@0: @deprecated Deprecated in 9.1 sl@0: @param aUri A reference to a parsed uri object. sl@0: @return A pointer to the newly created CUri16 object. sl@0: @post A fully constructed and initialized CUri16 object. sl@0: */ sl@0: EXPORT_C CUri16* CUri16::NewLC(const TUriC16& aUri) sl@0: { sl@0: CUri16* self = new (ELeave) CUri16(aUri); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Static factory constructor. Uses two phase construction and leaves nothing on the CleanupStack. sl@0: Creates a uri object which is empty. sl@0: sl@0: @since 6.0 sl@0: @deprecated Deprecated in 9.1 sl@0: @return A pointer to the newly created CUri16 object. sl@0: @post A fully constructed and initialized CUri16 object. sl@0: */ sl@0: EXPORT_C CUri16* CUri16::NewL() sl@0: { sl@0: CUri16* self = CUri16::NewLC(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Static factory constructor. Uses two phase construction and leaves a pointer to created object on sl@0: the CleanupStack. Creates a uri object which is empty. sl@0: sl@0: @since 6.0 sl@0: @deprecated Deprecated in 9.1 sl@0: @return A pointer to the newly created CUri16 object. sl@0: @post A fully constructed and initialized CUri16 object. sl@0: */ sl@0: EXPORT_C CUri16* CUri16::NewLC() sl@0: { sl@0: CUri16* self = new (ELeave) CUri16(TUriC16()); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Static factory constructor. This creates a CUri16 object that is an absolute uri resulting from a sl@0: reference uri being resolved against a base uri. sl@0: sl@0: @warning Ownership of created CUri16 object is transferred to caller. sl@0: @leave KUriErrBadBasePath if the base path is not an absolute path and not empty. sl@0: @since 6.0 sl@0: @deprecated Deprecated in 9.1 sl@0: @param aBaseUri A referece to the parsed base uri. sl@0: @param aRefUri A referece to the parsed reference uri. sl@0: @return A pointer to the newly created CUri16 object. sl@0: @pre The base uri must have an absolute or empty path, otherwise will leave sl@0: with KUriErrBadBasePath. sl@0: @post A fully constructed and initialized CUri16 object. sl@0: */ sl@0: EXPORT_C CUri16* CUri16::ResolveL(const TUriC16& aBaseUri, const TUriC16& aRefUri) sl@0: { sl@0: // Check for a base Uri sl@0: if( aBaseUri.UriDes().Compare(KNullDesC16) == 0 ) sl@0: { sl@0: // Empty base Uri - resolved Uri is the reference Uri sl@0: return NewL(aRefUri); sl@0: } sl@0: // See if ref has scheme and it is the same as base Uri sl@0: if( aRefUri.IsPresent(EUriScheme) && aRefUri.Compare(aBaseUri, EUriScheme) != 0 ) sl@0: { sl@0: // Ref has a scheme different to base Uri's - it is an absolute Uri sl@0: return NewL(aRefUri); sl@0: } sl@0: // Check for presence of components sl@0: TBool useBaseQuery = EFalse; sl@0: HBufC16* resolvedPath = FormResolvedPathLC(aBaseUri, aRefUri, useBaseQuery); sl@0: sl@0: // Put the Uri together sl@0: TUriC16 uri; sl@0: FormResolvedUri(uri.iComponent, aBaseUri, aRefUri, resolvedPath, useBaseQuery); sl@0: sl@0: // Create the resolved Uri and cleanup sl@0: CUri16* resolvedUri = NewL(uri); sl@0: CleanupStack::PopAndDestroy(resolvedPath); sl@0: sl@0: return resolvedUri; sl@0: } sl@0: sl@0: /** sl@0: Destructor. sl@0: sl@0: @since 6.0 sl@0: @deprecated Deprecated in 9.1 sl@0: */ sl@0: EXPORT_C CUri16::~CUri16() sl@0: { sl@0: delete iUriBuf; sl@0: } sl@0: sl@0: /** sl@0: Provides a reference to the parsed uri. Allows access to the non-modifying API for TUriC16. sl@0: sl@0: @since 6.0 sl@0: @deprecated Deprecated in 9.1 sl@0: @return A const reference to the parsed uri object. sl@0: */ sl@0: EXPORT_C const TUriC16& CUri16::Uri() const sl@0: { sl@0: return iUri; sl@0: } sl@0: sl@0: /** sl@0: Sets the specified component in the uri. The component is set to the value given in the argument sl@0: aData. If the specified component already exists then it is replaced with the new value. sl@0: sl@0: @warning The userinfo and port components can only be set if the host component sl@0: is present. Setting these components without a host component present will have no sl@0: effect on the uri. sl@0: @since 6.0 sl@0: @deprecated Deprecated in 9.1 sl@0: @param aData A descriptor pointer to the new value for the uri component. sl@0: @param aComponent An enum specifying the component to be set. sl@0: @pre Object is fully constructed. sl@0: @post The uri has the specified component set to the new value. sl@0: @Leave KErrArgument If aComponent goes out of range. sl@0: */ sl@0: EXPORT_C void CUri16::SetComponentL(const TDesC16& aData, TUriComponent aComponent) sl@0: { sl@0: // Update the appropriate component table entry sl@0: iUri.iComponent[aComponent].Set(aData); sl@0: sl@0: // Copy to the buffer by forming the uri sl@0: FormUriL(); sl@0: } sl@0: sl@0: /** sl@0: Removes the specified component from the uri. If the component does not exist then this function sl@0: does nothing. sl@0: sl@0: @warning If host is removed, then userinfo and port components will also sl@0: be removed. sl@0: @since 6.0 sl@0: @deprecated Deprecated in 9.1 sl@0: @param aComponent An enum specifying the component to be removed. sl@0: @pre Object is fully constructed. sl@0: @post The uri is updated to exclude the specified component. sl@0: */ sl@0: EXPORT_C void CUri16::RemoveComponentL(TUriComponent aComponent) sl@0: { sl@0: if( iUri.IsPresent(aComponent) ) sl@0: { sl@0: // Remove the component - set pointer to NULL and length to zero sl@0: iUri.iComponent[aComponent].Set(NULL,0); sl@0: sl@0: // Re-form buffer and component table sl@0: FormUriL(); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Constructor. First phase of two-phase construction method. Does non-allocating construction. sl@0: sl@0: @since 6.0 sl@0: @param aUri The parsed uri component information from which to create sl@0: the uri. sl@0: */ sl@0: sl@0: CUri16::CUri16(const TUriC16& aUri) sl@0: : CBase(), iUri(aUri) sl@0: { sl@0: } sl@0: sl@0: /** sl@0: Second phase of two-phase construction method. Does any allocations required to fully construct sl@0: the object. sl@0: sl@0: @since 6.0 sl@0: @pre First phase of construction is complete. sl@0: @post The object is fully constructed and initialized. sl@0: */ sl@0: void CUri16::ConstructL() sl@0: { sl@0: // Create the HBufC sl@0: FormUriL(); sl@0: } sl@0: sl@0: /** sl@0: Forms the uri from the parsed uri information. A copy of the parsed uri is created. The parsed uri sl@0: is changed to refer to the copy. sl@0: sl@0: @since 6.0 sl@0: @pre The parsed uri information is set. sl@0: @post The uri buffer is updated with the parsed uri information. sl@0: */ sl@0: void CUri16::FormUriL() sl@0: { sl@0: TBool isIPv6Host; sl@0: sl@0: // Calculate length of of the Uri sl@0: TInt length = CalculateUriLength(iUri.iComponent, isIPv6Host); sl@0: sl@0: // Create a temporary buffer and descriptor pointer to it sl@0: HBufC16* buf = HBufC16::NewL(length); sl@0: TPtr16 uri = buf->Des(); sl@0: sl@0: // Create the uri, updating the internal uri object sl@0: DoFormUri(uri, iUri.iComponent, isIPv6Host); sl@0: sl@0: // Update the internal buffer and descriptor pointer sl@0: delete iUriBuf; sl@0: iUriBuf = buf; sl@0: iUri.iUriDes.Set(iUriBuf->Des()); 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: Calculates the length of the uri from a list of the components. sl@0: sl@0: @since 6.0 sl@0: @param aComponent The array of descriptor pointers to the uri sl@0: components. sl@0: @param aIsIPv6Host ETrue if an IPv6 format host is used sl@0: @return The length of the uri including the required delimiters. sl@0: */ sl@0: template sl@0: TInt CalculateUriLength(const TPtrCType aComponent[], TBool& aIsIPv6Host) sl@0: { sl@0: TBool noAuthority = ETrue; sl@0: TInt length=0; sl@0: aIsIPv6Host=EFalse; sl@0: for( TInt i=0; i sl@0: void DoFormUri(TPtrType& aUri, TPtrCType aComponent[], TBool& aIsIPv6Host) sl@0: { sl@0: TBool isNetworkScheme = ETrue; sl@0: if( aComponent[EUriScheme].Ptr() ) sl@0: { sl@0: // Update the scheme sl@0: SetScheme(aUri, aComponent[EUriScheme]); sl@0: isNetworkScheme = IsNetworkScheme(aComponent[EUriScheme]); sl@0: } sl@0: if( aComponent[EUriHost].Ptr() ) sl@0: { sl@0: // Update the authority - only needed if there is a host; update userinfo, host and port sl@0: SetAuthority(aUri, aComponent[EUriUserinfo], aComponent[EUriHost], aComponent[EUriPort], aIsIPv6Host, isNetworkScheme); sl@0: } sl@0: else sl@0: { sl@0: // Ensure that there is no userinfo or port components if there is no host sl@0: // - set pointer to NULL and length to zero sl@0: aComponent[EUriUserinfo].Set(NULL,0); sl@0: aComponent[EUriPort].Set(NULL,0); sl@0: } sl@0: if( aComponent[EUriPath].Ptr() ) sl@0: { sl@0: // Update the path sl@0: SetPath(aUri, aComponent[EUriPath]); sl@0: } sl@0: if( aComponent[EUriQuery].Ptr() ) sl@0: { sl@0: // Update the query sl@0: SetQuery(aUri, aComponent[EUriQuery]); sl@0: } sl@0: if( aComponent[EUriFragment].Ptr() ) sl@0: { sl@0: // Update the fragment sl@0: SetFragment(aUri, aComponent[EUriFragment]); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Templated function to set the scheme in a uri. The output argument aUri points to the descriptor sl@0: buffer into which aScheme will be copied.The argument aScheme is then updated to point to the sl@0: copied version in aUri. sl@0: sl@0: @warning This function will panic with KUriErrBufferOverflow if there is not sl@0: enough space in the descriptor to append the scheme and the required delimiter. sl@0: @since 6.0 sl@0: @param aUri The descriptor pointer to buffer to be appended. sl@0: @param aScheme The descriptor pointer to the scheme component to be copied sl@0: and then updated. sl@0: @pre The buffer pointed to by aUri should be large enough to have aNewScheme sl@0: appended to it with the required delimiter. This can be obtained using CalculateUriLength(). sl@0: @post The uri buffer now includes a copy of aScheme and aScheme points to the sl@0: copy of the scheme component in aUri. sl@0: */ sl@0: template sl@0: void SetScheme(TPtrType& aUri, TPtrCType& aScheme) sl@0: { sl@0: __ASSERT_DEBUG(aUri.Length() + aScheme.Length() + 1 <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow)); sl@0: sl@0: // Append the scheme and delimiter sl@0: aUri.Append(aScheme); sl@0: aUri.Append(KSchemeDelimiter); sl@0: sl@0: // Update the component table to use the copy sl@0: aScheme.Set(aUri.Left(aScheme.Length())); sl@0: } sl@0: sl@0: /** sl@0: Templated function to set the authority in a uri. The output argument aUri points to the descriptor sl@0: buffer into which aUserinfo, aHost and aPort will be copied. The arguments aUserinfo, aHost and aPort sl@0: are updated to point to the copied versions in aUri. sl@0: sl@0: @warning This function will panic with KUriErrBufferOverflow if there sl@0: is not enough space in the descriptor to append the components and any required sl@0: delimiters. sl@0: @since 6.0 sl@0: @param aUri The descriptor pointer to buffer to be appended. sl@0: @param aUserinfo The descriptor pointer to the userinfo component to sl@0: be copied and then updated. sl@0: @param aHost The descriptor pointer to the host component to sl@0: be copied and then updated. sl@0: @param aPort The descriptor pointer to the port component to sl@0: be copied and then updated. sl@0: @param aIsIPv6Host ETrue if an IPv6 format host is used sl@0: @param aUseNetworkDelimiter EFalse if this is a SIP scheme otherwise ETrue sl@0: @pre The buffer pointed to by aUri should be large enough to have sl@0: aUserinfo, aHost and aPort appended to it with the required delimiters. sl@0: This can be obtained using CalculateUriLength(). sl@0: @post The uri buffer now includes a copy of aUserinfo, aHost and sl@0: aPort, and aUserinfo, aHost and aPort will refer to the copies versions in aUri. sl@0: */ sl@0: template sl@0: void SetAuthority(TPtrType& aUri, TPtrCType& aUserinfo, TPtrCType& aHost, TPtrCType& aPort, TBool& aIsIPv6Host, TBool aUseNetworkDelimiter) sl@0: { sl@0: __ASSERT_DEBUG(aUri.Length() + aHost.Length() + (aUseNetworkDelimiter ? KUriNetworkAuthorityDelimiterLength:0) <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow)); sl@0: sl@0: if (aUseNetworkDelimiter) sl@0: { sl@0: // If a network scheme append authority delimiter (TWO slash delimiters!) sl@0: aUri.Append(KSlashDelimiter); sl@0: aUri.Append(KSlashDelimiter); sl@0: } sl@0: sl@0: // Check for userinfo sl@0: if( aUserinfo.Ptr() ) sl@0: { sl@0: __ASSERT_DEBUG(aUri.Length() + aUserinfo.Length() + aHost.Length() + 1 <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow)); sl@0: sl@0: // Append userinfo and update the component table to use copy sl@0: aUri.Append(aUserinfo); sl@0: aUserinfo.Set(aUri.Right(aUserinfo.Length())); sl@0: sl@0: // Append delimiter sl@0: aUri.Append(KUserinfoDelimiter); sl@0: } sl@0: // There's always a host - append and update the component table to use the copy sl@0: sl@0: // Check if it's an IPv6 address sl@0: if ( aIsIPv6Host ) sl@0: { sl@0: aUri.Append(KIPv6UriOpenBrace); sl@0: aUri.Append(aHost); sl@0: aUri.Append(KIPv6UriCloseBrace); sl@0: // Dont include the braces in the host sl@0: // Position = (length of uri - length of host) - length of end brace sl@0: aHost.Set( aUri.Mid((aUri.Length()-aHost.Length())-1, aHost.Length()) ); sl@0: } sl@0: else sl@0: { sl@0: aUri.Append(aHost); sl@0: aHost.Set(aUri.Right(aHost.Length())); sl@0: } sl@0: sl@0: // Check for a port sl@0: if( aPort.Ptr() ) sl@0: { sl@0: __ASSERT_DEBUG(aUri.Length() + aPort.Length() + 1 <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow)); sl@0: sl@0: // Append delimiter sl@0: aUri.Append(KPortDelimiter); sl@0: sl@0: // Append port and update the component table to use copy sl@0: aUri.Append(aPort); sl@0: aPort.Set(aUri.Right(aPort.Length())); sl@0: } sl@0: } sl@0: /** sl@0: Templated function to set the path in a uri. The output argument aUri points to the descriptor sl@0: buffer into which aPath will be copied.The argument aPath is then updated to point to the copied sl@0: version in aUri. sl@0: sl@0: @warning This function will panic with KUriErrBufferOverflow if there sl@0: is not enough space in the descriptor to append the path. sl@0: @since 6.0 sl@0: @param aUri The descriptor pointer to buffer to be appended. sl@0: @param aPath The descriptor pointer to the path component to be copied sl@0: and then updated. sl@0: @pre The buffer pointed to by aUri should be large enough to have sl@0: aPath appended to it. This can be obtained using CalculateUriLength(). sl@0: @post The uri buffer now includes a copy of aPath and aPath points to the sl@0: copy of the path component in aUri. sl@0: */ sl@0: template sl@0: void SetPath(TPtrType& aUri, TPtrCType& aPath) sl@0: { sl@0: __ASSERT_DEBUG(aUri.Length() + aPath.Length() <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow)); sl@0: sl@0: // Append the path sl@0: aUri.Append(aPath); sl@0: sl@0: // Update the component table sl@0: aPath.Set(aUri.Right(aPath.Length())); sl@0: } sl@0: sl@0: /** sl@0: Templated function to set the query in a uri. The output argument aUri points to the descriptor sl@0: buffer into which aQuery will be copied. The argument aQuery is then updated to point to the copied sl@0: version in aUri. sl@0: sl@0: @warning This function will panic with KUriErrBufferOverflow if there sl@0: is not enough space in the descriptor to append the query and the delimiter. sl@0: @since 6.0 sl@0: @param aUri The descriptor pointer to buffer to be appended. sl@0: @param aQuery The descriptor pointer to the query component to be copied sl@0: and then updated. sl@0: @pre The buffer pointed to by aUri should be large enough to have sl@0: aQuery appended to it. This can be obtained using CalculateUriLength(). sl@0: @post The uri buffer now includes a copy of aQuery and aQuery points to the sl@0: copy of the query component in aUri. sl@0: */ sl@0: template sl@0: void SetQuery(TPtrType& aUri, TPtrCType& aQuery) sl@0: { sl@0: __ASSERT_DEBUG(aUri.Length() + aQuery.Length() + 1 <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow)); sl@0: sl@0: // Append delimiter and the query sl@0: aUri.Append(KQueryDelimiter); sl@0: aUri.Append(aQuery); sl@0: sl@0: // Update the component table sl@0: aQuery.Set(aUri.Right(aQuery.Length())); sl@0: } sl@0: sl@0: /** sl@0: Templated function to set the fragment in a uri. The output argument aUri points to the descriptor sl@0: buffer into which aFragment will be copied. The argument aFragment is then updated to point to the sl@0: copied version in aUri. sl@0: sl@0: @warning This function will panic with KUriErrBufferOverflow if there sl@0: is not enough space in the descriptor to append the fragment and the delimiter. sl@0: @since 6.0 sl@0: @param aUri The descriptor pointer to buffer to be appended. sl@0: @param aFragment The descriptor pointer to the fragment component sl@0: to be copied and then updated. sl@0: @pre The buffer pointed to by aUri should be large enough to have sl@0: aFragment appended to it. This can be obtained using CalculateUriLength(). sl@0: @post The uri buffer now includes a copy of aFragment and aFragment points sl@0: to the copy of the fragment component in aUri. sl@0: */ sl@0: template sl@0: void SetFragment(TPtrType& aUri, TPtrCType& aFragment) sl@0: { sl@0: __ASSERT_DEBUG(aUri.Length() + aFragment.Length() + 1 <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow)); sl@0: sl@0: // Append delimiter and the fragment sl@0: aUri.Append(KFragmentDelimiter); sl@0: aUri.Append(aFragment); sl@0: sl@0: // Update the component table sl@0: aFragment.Set(aUri.Right(aFragment.Length())); sl@0: } sl@0: sl@0: /** sl@0: Forms the resolved path. Checks to see if the base query needs to be used in the resolved uri. sl@0: The pointer to the resolved path is left on the cleanup stack. sl@0: sl@0: @since 6.0 sl@0: @param aBaseUri The base uri. sl@0: @param aRefUri The reference uri. sl@0: @param aUseBaseQuery An output argument specifying whether the base sl@0: query should be used in the resolved uri. sl@0: @return A pointer to a buffer that contains the resolved path. sl@0: */ sl@0: template sl@0: HBufCType* FormResolvedPathLC(const TUriCType& aBaseUri, const TUriCType& aRefUri, TBool& aUseBaseQuery) sl@0: { sl@0: HBufCType* resolvedPath = NULL; sl@0: if( !aRefUri.IsPresent(EUriScheme) && !aRefUri.IsPresent(EUriHost) && !aRefUri.Extract(EUriPath).Length() && !aRefUri.IsPresent(EUriQuery) ) sl@0: { sl@0: // Ref is just a fragment sl@0: aUseBaseQuery = ETrue; sl@0: resolvedPath = aBaseUri.Extract(EUriPath).AllocLC(); sl@0: } sl@0: else if( aRefUri.IsPresent(EUriHost) ) sl@0: { sl@0: // Ref is a network path sl@0: resolvedPath = aRefUri.Extract(EUriPath).AllocLC(); sl@0: } sl@0: else sl@0: { sl@0: // Need to some path resolving... sl@0: resolvedPath = ResolvePathsL(aBaseUri.Extract(EUriPath), aRefUri.Extract(EUriPath)); sl@0: CleanupStack::PushL(resolvedPath); sl@0: } sl@0: return resolvedPath; sl@0: } sl@0: sl@0: /** sl@0: Cleans up a resolved path. This deals with occurences of '.' and '..' where these are complete sl@0: path segments. sl@0: sl@0: @since 6.0 sl@0: @param aResolvedPath The delimited data object that contains the sl@0: resolved path. sl@0: @pre The input/output argument contains the path to be cleaned. sl@0: @post The resolved path has had all the occurences of '.' and '..' sl@0: processed and has been updated to contain the cleaned path. sl@0: */ sl@0: template sl@0: void CleanResolvedPathL(CDelimitedDataBaseType* aResolvedPath) sl@0: { sl@0: // Create a modifiable path object for resolved path sl@0: aResolvedPath->Parse(); sl@0: sl@0: TBool done = EFalse; sl@0: while( !done ) sl@0: { sl@0: // Get the next segment sl@0: TPtrCType segment; sl@0: TInt more = aResolvedPath->Parser().Peek(segment); sl@0: sl@0: if( more == KErrNotFound ) sl@0: { sl@0: // No more segments - done sl@0: done = ETrue; sl@0: } sl@0: else if( IsParentDir(segment) ) sl@0: { sl@0: // Found a '..' - remove '..' from path, and remove previous segment sl@0: aResolvedPath->RemoveCurrentL(); sl@0: if( aResolvedPath->Parser().Dec() == KErrNotFound ) sl@0: { sl@0: // No previous directory - put back '..' and stop sl@0: InsertParentDirL(aResolvedPath); sl@0: done = ETrue; sl@0: } sl@0: else sl@0: { sl@0: // Remove the parent directory sl@0: aResolvedPath->RemoveCurrentL(); sl@0: if( aResolvedPath->Parser().Eos() ) sl@0: { sl@0: // '..' is the last segment - add a '/' to the path (add empty segment) sl@0: aResolvedPath->AddBackDelimiterL(); sl@0: done = ETrue; sl@0: } sl@0: } sl@0: } sl@0: else if( IsSameDir(segment) ) sl@0: { sl@0: // Found a '.' - remove -.- from the path sl@0: aResolvedPath->RemoveCurrentL(); sl@0: if( aResolvedPath->Parser().Eos() ) sl@0: { sl@0: // '..' is the last segment - add a '/' to the path (add empty segment) sl@0: aResolvedPath->AddBackDelimiterL(); sl@0: done = ETrue; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // Segment wasn't '.' or '..' - parse to next segment sl@0: aResolvedPath->Parser().Inc(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Forms the resolved uri. Sets the components for the resolved uri from those in the base uri and sl@0: the reference uri. The resolved path is given by the input argument aResolvedPath sl@0: sl@0: @since 6.0 sl@0: @param aComponent The array of components to be set for the resolved uri. sl@0: @param aBaseUri The base uri. sl@0: @param aRefUri The reference uri. sl@0: @param aResolvedPath The resolved path. sl@0: @param aUseBaseQuery A boolean indicating whether the base query sl@0: should be used. sl@0: */ sl@0: template sl@0: void FormResolvedUri(TPtrCType aComponent[], const TUriCType& aBaseUri, const TUriCType& aRefUri, const HBufCType* aResolvedPath, TBool aUseBaseQuery) sl@0: { sl@0: // Scheme... sl@0: if( aBaseUri.IsPresent(EUriScheme) ) sl@0: { sl@0: // Use the base scheme sl@0: aComponent[EUriScheme].Set(aBaseUri.Extract(EUriScheme)); sl@0: } sl@0: // Authority sl@0: if( aRefUri.IsPresent(EUriHost) ) sl@0: { sl@0: // Use the ref host, userinfo and port - must set host first sl@0: aComponent[EUriHost].Set(aRefUri.Extract(EUriHost)); sl@0: aComponent[EUriUserinfo].Set(aRefUri.Extract(EUriUserinfo)); sl@0: aComponent[EUriPort].Set(aRefUri.Extract(EUriPort)); sl@0: } sl@0: else if( aBaseUri.IsPresent(EUriHost) ) sl@0: { sl@0: // Use the base host, userinfo and port - must set host first sl@0: aComponent[EUriHost].Set(aBaseUri.Extract(EUriHost)); sl@0: aComponent[EUriUserinfo].Set(aBaseUri.Extract(EUriUserinfo)); sl@0: aComponent[EUriPort].Set(aBaseUri.Extract(EUriPort)); sl@0: } sl@0: // Path... sl@0: aComponent[EUriPath].Set(*aResolvedPath); sl@0: sl@0: // Query... sl@0: if( aUseBaseQuery && aBaseUri.IsPresent(EUriQuery) ) sl@0: { sl@0: // Use the query from the base sl@0: aComponent[EUriQuery].Set(aBaseUri.Extract(EUriQuery)); sl@0: } sl@0: else if( aRefUri.IsPresent(EUriQuery) ) sl@0: { sl@0: // Use the query from the ref sl@0: aComponent[EUriQuery].Set(aRefUri.Extract(EUriQuery)); sl@0: } sl@0: // Fragment sl@0: if( aRefUri.IsPresent(EUriFragment) ) sl@0: { sl@0: // Use the fragment from the ref sl@0: aComponent[EUriFragment].Set(aRefUri.Extract(EUriFragment)); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // sl@0: // Implemetation of LOCAL functions sl@0: // sl@0: // sl@0: sl@0: /** sl@0: Function used to resolve a base path (aBasePath) against a reference path (aRefPath), sl@0: as described by RFC2396. sl@0: sl@0: @since 6.0 sl@0: @param aBasePath A descriptor reference to the base path. sl@0: @param aRefPath A descriptor reference to the reference path. sl@0: @return A pointer to a buffer containing the resolve path. sl@0: @leave KUriErrBadBasePath if the base path is not an absolute path and not empty. sl@0: */ sl@0: HBufC8* ResolvePathsL(const TDesC8& aBasePath, const TDesC8& aRefPath) sl@0: { sl@0: TInt refLength = aRefPath.Length(); sl@0: if( refLength && aRefPath[0] == KSlashDelimiter ) sl@0: { sl@0: // Relative path is absolute - that is the resolved path sl@0: return aRefPath.AllocL(); sl@0: } sl@0: // Ok got work to do - base path must be absolute (check 1st char) or empty sl@0: if( aBasePath.Length() && aBasePath[0] != KSlashDelimiter ) sl@0: { sl@0: // Base path not empty and not abosolute - bad base path sl@0: User::Leave(KUriUtilsErrBadBasePath); sl@0: } sl@0: // Create a modifiable path object for resolved path sl@0: CDelimitedPath8* resolvedPath = CDelimitedPath8::NewLC(aBasePath); sl@0: sl@0: // Check for empty ref path - use all of base path if empty sl@0: if( refLength ) sl@0: { sl@0: // Not empty - ensure that base path's last segment is removed and add reference sl@0: resolvedPath->PopBackL(); sl@0: resolvedPath->PushBackL(aRefPath); sl@0: } sl@0: // Clean up the path to resolve occurences of '..' and '.' - parser path first sl@0: CleanResolvedPathL(resolvedPath); sl@0: sl@0: // Return pointer to HBufC with path sl@0: HBufC8* path = resolvedPath->Parser().Des().AllocL(); sl@0: CleanupStack::PopAndDestroy(resolvedPath); sl@0: return path; sl@0: } sl@0: sl@0: /** sl@0: Function used to resolve a base path (aBasePath) against a reference path (aRefPath), sl@0: as described by RFC2396. sl@0: sl@0: @since 6.0 sl@0: @param aBasePath A descriptor reference to the base path. sl@0: @param aRefPath A descriptor reference to the reference path. sl@0: @return A pointer to a buffer containing the resolve path. sl@0: @leave KUriErrBadBasePath if the base path is not an absolute path and not empty. sl@0: */ sl@0: HBufC16* ResolvePathsL(const TDesC16& aBasePath, const TDesC16& aRefPath) sl@0: { sl@0: TInt refLength = aRefPath.Length(); sl@0: if( refLength && aRefPath[0] == KSlashDelimiter ) sl@0: { sl@0: // Relative path is absolute - that is the resolved path sl@0: return aRefPath.AllocL(); sl@0: } sl@0: // Ok got work to do - base path must be absolute (check 1st char) or empty sl@0: if( aBasePath.Length() && aBasePath[0] != KSlashDelimiter ) sl@0: { sl@0: // Base path not empty and not abosolute - bad base path sl@0: User::Leave(KUriUtilsErrBadBasePath); sl@0: } sl@0: // Create a modifiable path object for resolved path sl@0: CDelimitedPath16* resolvedPath = CDelimitedPath16::NewLC(aBasePath); sl@0: sl@0: // Check for empty ref path - use all of base path if empty sl@0: if( refLength ) sl@0: { sl@0: // Not empty - ensure that base path's last segment is removed and add reference sl@0: resolvedPath->PopBackL(); sl@0: resolvedPath->PushBackL(aRefPath); sl@0: } sl@0: // Clean up the path to resolve occurences of '..' and '.' - parser path first sl@0: CleanResolvedPathL(resolvedPath); sl@0: sl@0: // Return pointer to HBufC with path sl@0: HBufC16* path = resolvedPath->Parser().Des().AllocL(); sl@0: CleanupStack::PopAndDestroy(resolvedPath); sl@0: return path; sl@0: } sl@0: sl@0: /** sl@0: Checks if the segment is '.' (8-bit version). sl@0: sl@0: @since 6.0 sl@0: @param aSegment A descriptor with the segment to check. sl@0: @return A boolean value of ETrue if the segment is '.', EFalse if not. sl@0: */ sl@0: TBool IsSameDir(const TDesC8& aSegment) sl@0: { sl@0: _LIT8(KSameDir, "."); sl@0: return (aSegment.Compare(KSameDir) == 0); sl@0: } sl@0: sl@0: /** sl@0: Checks if the segment is '.' (16-bit version). sl@0: sl@0: @since 6.0 sl@0: @param aSegment A descriptor with the segment to check. sl@0: @return A boolean value of ETrue if the segment is '.', EFalse if not. sl@0: */ sl@0: TBool IsSameDir(const TDesC16& aSegment) sl@0: { sl@0: _LIT16(KSameDir, "."); sl@0: return (aSegment.Compare(KSameDir) == 0); sl@0: } sl@0: sl@0: /** sl@0: Checks if the segment is '..' (8-bit version). sl@0: sl@0: @since 6.0 sl@0: @param aSegment A descriptor with the segment to check. sl@0: @return A boolean value of ETrue if the segment is '..', EFalse if not. sl@0: */ sl@0: TBool IsParentDir(const TDesC8& aSegment) sl@0: { sl@0: _LIT8(KParentDir, ".."); sl@0: return (aSegment.Compare(KParentDir) == 0); sl@0: } sl@0: sl@0: /** sl@0: Checks if the segment is '..' (16-bit version). sl@0: sl@0: @since 6.0 sl@0: @param aSegment A descriptor with the segment to check. sl@0: @return A boolean value of ETrue if the segment is '..', EFalse if not. sl@0: */ sl@0: TBool IsParentDir(const TDesC16& aSegment) sl@0: { sl@0: _LIT16(KParentDir, ".."); sl@0: return (aSegment.Compare(KParentDir) == 0); sl@0: } sl@0: sl@0: /** sl@0: Inserts the segment '..' at the current parsed position (8-bit version). sl@0: sl@0: @since 6.0 sl@0: @param aResolvedPath The delimited data object to have the segment sl@0: inserted. sl@0: @pre The delimited data object must be parsed to the position where sl@0: the segment is to be inserted. sl@0: @post The segment '..' has been inserted at the current position. sl@0: */ sl@0: void InsertParentDirL(CDelimitedDataBase8* aResolvedPath) sl@0: { sl@0: _LIT8(KParentDir, ".."); sl@0: aResolvedPath->InsertCurrentL(KParentDir); sl@0: } sl@0: sl@0: /** sl@0: Inserts the segment '..' at the current parsed position (16-bit version). sl@0: sl@0: @since 6.0 sl@0: @param aResolvedPath The delimited data object to have the segment sl@0: inserted. sl@0: @pre The delimited data object must be parsed to the position where sl@0: the segment is to be inserted. sl@0: @post The segment '..' has been inserted at the current position. sl@0: */ sl@0: void InsertParentDirL(CDelimitedDataBase16* aResolvedPath) sl@0: { sl@0: _LIT16(KParentDir, ".."); sl@0: aResolvedPath->InsertCurrentL(KParentDir); sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // File URI Implementation - CUri8 sl@0: // sl@0: // sl@0: sl@0: /** sl@0: Initializes the file URI components (scheme, empty hostname and path). sl@0: sl@0: It uses GenerateFileUriPathL() to generate a file Uri path using the filename and drive. sl@0: sl@0: @since 9.1 sl@0: @param aFileName A reference to a filename sl@0: @param aDrive A drive number. This is a TFileUriFlags value. sl@0: @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive. sl@0: This is a TFileUriFlags value. sl@0: @pre Object fully constructed sl@0: @post The object is initialized with file URI components. sl@0: */ sl@0: void CUri8::InitializeFileUriComponentsL(const TDesC& aFileName, TDriveNumber aDrive, TUint aFlags) sl@0: { sl@0: HBufC* uriPath16 = GenerateFileUriPathL(aFileName, aDrive, aFlags); sl@0: CleanupStack::PushL(uriPath16); sl@0: HBufC8* uriPath = EscapeUtils::ConvertFromUnicodeToUtf8L(*uriPath16); sl@0: CleanupStack::PopAndDestroy(uriPath16); sl@0: CleanupStack::PushL(uriPath); sl@0: HBufC8* escpedUriPath = EscapeUtils::EscapeEncodeL(*uriPath, EscapeUtils::EEscapeNormal); sl@0: CleanupStack::PopAndDestroy(uriPath); sl@0: CleanupStack::PushL(escpedUriPath); sl@0: sl@0: //SetComponent is not used in order to increase efficiency, by avoiding overhead of length calculation, sl@0: //tmp buffer allocation and updation of internal uri object, internal buffer & descriptor pointer sl@0: //for each SetComponent call sl@0: iUri.iComponent[EUriPath].Set(*escpedUriPath); sl@0: iUri.iComponent[EUriHost].Set(KNullDesC8); sl@0: iUri.iComponent[EUriScheme].Set(KFileUriScheme8); sl@0: FormUriL(); sl@0: sl@0: CleanupStack::PopAndDestroy(escpedUriPath); sl@0: } sl@0: sl@0: /** sl@0: Allocates and constructs a file URI object for a specified file. sl@0: sl@0: - If the file exists on a fixed drive, then the file URI takes the form: 'file://\/\'. sl@0: - If the file exists on a removable media drive, then the file URI takes the form: 'file://ext-media/\'. sl@0: sl@0: @since 9.1 sl@0: @param aFullFileName A reference to a fully qualified filename sl@0: @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive. sl@0: This is a TFileUriFlags value. sl@0: @return A pointer to the newly created file URI (CUri8) object. sl@0: @post A fully constructed and initialized file URI (CUri8) object. sl@0: */ sl@0: EXPORT_C CUri8* CUri8::CreateFileUriL(const TDesC& aFullFileName, TUint aFlags) sl@0: { sl@0: //It should be called to construct a file URI for a public file stored on a fix drive sl@0: // or on a removable media drive only sl@0: __ASSERT_ALWAYS( ((aFlags == 0) || (aFlags & EExtMedia)), User::Panic(KFileUriPanicCategory, KUriUtilsCannotConvert) ); sl@0: sl@0: CUri8* self = CUri8::NewLC(); sl@0: self->InitializeFileUriComponentsL(aFullFileName, EDriveA, aFlags); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Allocates and constructs a file URI object for a file that is private to the application. sl@0: sl@0: - If the file exists on a fixed drive, then the file URI takes the form 'file://private/\/'. sl@0: - If the file exists on a removable media drive, then the file URI takes the form 'file://private/ext-media/\'. sl@0: sl@0: @since 9.1 sl@0: @param aRelativeFileName A reference to the filename relative to the application's private directory. sl@0: @param aDrive Drive number, if the private file stored on fixed drive, otherwise not used sl@0: This is a TDriveNumber value sl@0: @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive. sl@0: This is a TFileUriFlags value. sl@0: @return A pointer to the newly created file URI (CUri8) object. sl@0: @post A fully constructed and initialized file URI (CUri8) object. sl@0: */ sl@0: sl@0: sl@0: EXPORT_C CUri8* CUri8::CreatePrivateFileUriL(const TDesC& aRelativeFileName, TDriveNumber aDrive, TInt aFlags) sl@0: { sl@0: //It should be called to construct a file URI for the application's private file stored on a fix drive sl@0: // or on a removable media drive only sl@0: __ASSERT_ALWAYS( (((aFlags == 0) || (aFlags & EExtMedia)) && (aDrive >= EDriveA && aDrive <= EDriveZ)), User::Panic(KFileUriPanicCategory, KUriUtilsCannotConvert) ); sl@0: sl@0: CUri8* self = CUri8::NewLC(); sl@0: self->InitializeFileUriComponentsL(aRelativeFileName, aDrive, aFlags|EPrivate); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // File URI Implementation - CUri16 sl@0: // sl@0: // sl@0: sl@0: /** sl@0: Initializes the file URI components (scheme, empty hostname and path). sl@0: sl@0: It uses GenerateFileUriPathL() to generate a file Uri path using the filename and drive. sl@0: sl@0: @since 9.1 sl@0: @param aFileName A reference to a filename sl@0: @param aDrive A drive number. This is a TFileUriFlags value. sl@0: @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive. sl@0: This is a TFileUriFlags value. sl@0: @pre Object fully constructed sl@0: @post The object is initialized with file URI components. sl@0: */ sl@0: void CUri16::InitializeFileUriComponentsL(const TDesC& aFileName, TDriveNumber aDrive, TUint aFlags) sl@0: { sl@0: HBufC* uriPath = GenerateFileUriPathL(aFileName, aDrive, aFlags); sl@0: CleanupStack::PushL(uriPath); sl@0: sl@0: HBufC8* uriPath8 = EscapeUtils::ConvertFromUnicodeToUtf8L(*uriPath); sl@0: CleanupStack::PopAndDestroy(uriPath); sl@0: CleanupStack::PushL(uriPath8); sl@0: sl@0: HBufC8* escapedUriPath8 = EscapeUtils::EscapeEncodeL(*uriPath8, EscapeUtils::EEscapeNormal); sl@0: CleanupStack::PopAndDestroy(uriPath8); sl@0: CleanupStack::PushL(escapedUriPath8); sl@0: sl@0: HBufC* escapedUriPath = HBufC::NewLC(escapedUriPath8->Length()); sl@0: escapedUriPath->Des().Copy(*escapedUriPath8); sl@0: sl@0: //SetComponent is not used in order to increase efficiency, by avoiding overhead of length calculation, sl@0: //tmp buffer allocation and updation of internal uri object, internal buffer & descriptor pointer sl@0: //for each SetComponent call sl@0: iUri.iComponent[EUriPath].Set(*escapedUriPath); sl@0: iUri.iComponent[EUriHost].Set(KNullDesC16); sl@0: iUri.iComponent[EUriScheme].Set(KFileUriScheme16); sl@0: FormUriL(); sl@0: sl@0: CleanupStack::PopAndDestroy(escapedUriPath); sl@0: CleanupStack::PopAndDestroy(escapedUriPath8); sl@0: } sl@0: sl@0: /** sl@0: Allocates and constructs a file URI object for a specified file. sl@0: sl@0: - If the file exists on a fixed drive, then the file URI takes the form: 'file://\/\'. sl@0: - If the file exists on a removable media drive, then the file URI takes the form: 'file://ext-media/\'. sl@0: sl@0: @since 9.1 sl@0: @param aFullFileName A reference to a fully qualified filename sl@0: @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive. sl@0: This is a TFileUriFlags value. sl@0: @return A pointer to the newly created file URI (CUri16) object. sl@0: @post A fully constructed and initialized file URI (CUri16) object. sl@0: */ sl@0: EXPORT_C CUri16* CUri16::CreateFileUriL(const TDesC& aFullFileName, TUint aFlags) sl@0: { sl@0: //It should be called to construct a file URI for a public file stored on a fix drive sl@0: // or on a removable media drive only sl@0: __ASSERT_ALWAYS( ((aFlags == 0) || (aFlags & EExtMedia)), User::Panic(KFileUriPanicCategory, KUriUtilsCannotConvert) ); sl@0: sl@0: CUri16* self = CUri16::NewLC(); sl@0: self->InitializeFileUriComponentsL(aFullFileName, EDriveA, aFlags); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: Allocates and constructs a file URI object for a file that is private to the application. sl@0: sl@0: - If the file exists on a fixed drive, then the file URI takes the form 'file://private/\/'. sl@0: - If the file exists on a removable media drive, then the file URI takes the form 'file://private/ext-media/\'. sl@0: sl@0: @since 9.1 sl@0: @param aRelativeFileName A reference to the filename relative to the application's private directory. sl@0: @param aDrive Drive number, if the private file stored on fixed drive, otherwise not used sl@0: This is a TDriveNumber value sl@0: @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive. sl@0: This is a TFileUriFlags value. sl@0: @return A pointer to the newly created file URI (CUri16) object. sl@0: @post A fully constructed and initialized file URI (CUri16) object. sl@0: */ sl@0: sl@0: sl@0: EXPORT_C CUri16* CUri16::CreatePrivateFileUriL(const TDesC& aRelativeFileName, TDriveNumber aDrive, TInt aFlags) sl@0: { sl@0: //It should be called to construct a file URI for the application's private file stored on a fix drive sl@0: // or on a removable media drive only sl@0: __ASSERT_ALWAYS( (((aFlags == 0) || (aFlags & EExtMedia)) && (aDrive >= EDriveA && aDrive <= EDriveZ)), User::Panic(KFileUriPanicCategory, KUriUtilsCannotConvert) ); sl@0: sl@0: CUri16* self = CUri16::NewLC(); sl@0: self->InitializeFileUriComponentsL(aRelativeFileName, aDrive, aFlags|EPrivate); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // Implemetation of LOCAL functions for the File URI sl@0: // sl@0: // sl@0: sl@0: /** sl@0: Function used to generate 16bit file uri using 1st parameter aFileName and sl@0: 2nd parameter aDrive for the application's private or a public file. sl@0: sl@0: This is called by API CreateFileUri() and CreatePrivateFileUri()to sl@0: generate a filename. sl@0: sl@0: Note: The space allocated for the returned descriptor will likely be larger sl@0: than the length of the descriptor sl@0: sl@0: @leave KErrBadName A provided Drivename or filename is not valid sl@0: @since 9.1 sl@0: @param aFileName A descriptor reference to the filename. sl@0: @param aDrive A descriptor reference to drive letter. sl@0: @param aFlags A flag to indicate the private or a public file exists on removable media or a fixed drive. sl@0: @return A pointer to a buffer containing the resolved fully qualified filename. sl@0: */ sl@0: HBufC* GenerateFileUriPathL(const TDesC& aFileName, TDriveNumber aDrive, TUint aFlags) sl@0: { sl@0: TInt origLength = aFileName.Length(); sl@0: sl@0: //Leaves with KErrBadName if filename length is out of range sl@0: if (origLength == 0 || origLength > KMaxFileName) sl@0: { sl@0: User::Leave(KErrBadName); sl@0: } sl@0: sl@0: TPtrC filename(aFileName); sl@0: sl@0: //extract drive letter and remove drive "x:" from filename sl@0: TUint drive = filename[0]; sl@0: sl@0: // hasDrive means it begins with a drive, e.g. "c:" sl@0: const TBool hasDrive = ((drive >= 'A' && drive <= 'Z') || (drive >= 'a' && drive <= 'z')) && (filename[1] == KDriveSeparator); sl@0: // hasTopPath means it begins with a \ (possibly after the drive) sl@0: const TBool hasTopPath = (hasDrive && (filename[2] == KFilePathSeparator)) || (!hasDrive && (drive == TUint(KFilePathSeparator) )); sl@0: sl@0: TInt skip = KDefaultPath().Length(); // skip leading ":\" by default sl@0: if(aFlags & TUint(EPrivate)) sl@0: { sl@0: skip = (hasDrive ? (KDefaultPath().Length() - 1) : 0) + (hasTopPath ? 1 : 0) ; sl@0: } sl@0: else sl@0: { sl@0: // if not private then it should have valid drive i.e. ":\" sl@0: if (!(hasDrive && hasTopPath)) sl@0: { sl@0: User::Leave(KErrBadName); sl@0: } sl@0: } sl@0: sl@0: if(skip) sl@0: { sl@0: filename.Set(aFileName.Right(origLength - skip)); sl@0: } sl@0: sl@0: TInt uriLen = aFileName.Length() + KExtMedia().Length() + KPrivate().Length() + 1 /* for drive letter */; sl@0: sl@0: HBufC* fileUri = HBufC::NewLC(uriLen); sl@0: TPtr fileUriPtr = fileUri->Des(); sl@0: fileUriPtr.Append(KUriPathSeparator); sl@0: sl@0: if (aFlags & TUint(EPrivate)) sl@0: { sl@0: fileUriPtr.Append(KPrivate); sl@0: drive = TInt16('A' + aDrive); sl@0: } sl@0: sl@0: if (aFlags & EExtMedia) sl@0: { sl@0: fileUriPtr.Append(KExtMedia); sl@0: } sl@0: else sl@0: { sl@0: fileUriPtr.Append(drive); sl@0: fileUriPtr.Append(KUriPathSeparator); sl@0: } sl@0: sl@0: fileUriPtr.Append(filename); sl@0: sl@0: //Convert "\" to "/" sl@0: ChangePathSeparator(fileUriPtr, KFilePathSeparator, KUriPathSeparator); sl@0: sl@0: //Handling "./" and "../" in the file URI path or resolving the URI path sl@0: CDelimitedPath16* resolvedPath = CDelimitedPath16::NewLC(fileUriPtr); sl@0: // Clean up the path to resolve occurences of '..' and '.' sl@0: CleanResolvedPathL(resolvedPath); sl@0: fileUriPtr.Copy(resolvedPath->Parser().Des()); // new path will always be shorter than old one sl@0: CleanupStack::PopAndDestroy(resolvedPath); sl@0: sl@0: CleanupStack::Pop(fileUri); sl@0: return fileUri; sl@0: }