First public contribution.
1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include <escapeutils.h>
19 #include <delimitedpath8.h>
20 #include <delimitedpath16.h>
21 #include <uriutilscommon.h>
24 #include "UriUtilsInternal.h"
25 #include "TUriCInternal.h"
26 #include "CUriInternal.h"
31 _LIT(KUriPanicCategory,"URI-CURI");
36 _LIT(KFileUriPanicCategory,"FILEURI-CURI");
43 // Implementation of CUri8
48 Static factory constructor. Uses two phase construction and leaves nothing on the
49 CleanupStack. Creates a uri object which is a copy of the input parameter aUri.
52 @param aUri A reference to a parsed uri object.
53 @return A pointer to the newly created CUri8 object.
54 @post A fully constructed and initialized CUri8 object.
56 EXPORT_C CUri8* CUri8::NewL(const TUriC8& aUri)
58 CUri8* self = CUri8::NewLC(aUri);
59 CleanupStack::Pop(self);
64 Static factory constructor. Uses two phase construction and leaves a pointer to
65 created object on the CleanupStack. Creates a uri object which is a copy of the
69 @param aUri A reference to a parsed uri object.
70 @return A pointer to the newly created CUri8 object.
71 @post A fully constructed and initialized CUri8 object.
73 EXPORT_C CUri8* CUri8::NewLC(const TUriC8& aUri)
75 CUri8* self = new (ELeave) CUri8(aUri);
76 CleanupStack::PushL(self);
82 Static factory constructor. Uses two phase construction and leaves nothing on the
83 CleanupStack. Creates a uri object which is empty.
86 @return A pointer to the newly created CUri8 object.
87 @post A fully constructed and initialized CUri8 object.
89 EXPORT_C CUri8* CUri8::NewL()
91 CUri8* self = CUri8::NewLC();
92 CleanupStack::Pop(self);
97 Static factory constructor. Uses two phase construction and leaves a pointer to created
98 object on the CleanupStack. Creates a uri object which is empty.
101 @return A pointer to the newly created CUri8 object.
102 @post A fully constructed and initialized CUri8 object.
104 EXPORT_C CUri8* CUri8::NewLC()
106 CUri8* self = new (ELeave) CUri8(TUriC8());
107 CleanupStack::PushL(self);
113 Static factory constructor. This creates a CUri8 object that is an absolute uri resulting
114 from a reference uri being resolved against a base uri.
116 @warning Ownership of created CUri8 object is transferred to the caller.
117 @leave KUriErrBadBasePath if the base path is not an absolute path and not empty.
119 @param aBaseUri A referece to the parsed base uri.
120 @param aRefUri A referece to the parsed reference uri.
121 @return A pointer to the newly created CUri8 object.
122 @pre The base uri must have an absolute or empty path, otherwise will leave
123 with KUriErrBadBasePath.
124 @post A fully constructed and initialized CUri8 object.
126 EXPORT_C CUri8* CUri8::ResolveL(const TUriC8& aBaseUri, const TUriC8& aRefUri)
128 // Check for a base Uri
129 if( aBaseUri.UriDes().Compare(KNullDesC8) == 0 )
131 // Empty base Uri - resolved Uri is the reference Uri
132 return NewL(aRefUri);
134 // See if ref has scheme and it is the same as base Uri
135 if( aRefUri.IsPresent(EUriScheme) && (aRefUri.Compare(aBaseUri, EUriScheme) != 0) )
137 // Ref has a scheme different to base Uri's - it is an absolute Uri
138 return NewL(aRefUri);
140 // Check for presence of components
141 TBool useBaseQuery = EFalse;
142 HBufC8* resolvedPath = FormResolvedPathLC<HBufC8>(aBaseUri, aRefUri, useBaseQuery);
144 //Removes dot segemnts in Resolved uri as specified in RFC3986 section 5.2.
145 RemoveExtraneousDotSegmentsL(resolvedPath);
147 // Put the Uri together
149 FormResolvedUri(uri.iComponent, aBaseUri, aRefUri, resolvedPath, useBaseQuery);
151 // Create the resolved Uri and cleanup
152 CUri8* resolvedUri = NewL(uri);
153 CleanupStack::PopAndDestroy(resolvedPath);
163 EXPORT_C CUri8::~CUri8()
169 Provides a reference to the parsed uri. Allows access to the non-modifying API for TUriC8.
172 @return A const reference to the parsed uri object.
174 EXPORT_C const TUriC8& CUri8::Uri() const
180 Intended Usage : Sets the specified component in the uri. The component is set to the value
181 given in the argument aData. If the specified component already exists then it is replaced
184 @warning The userinfo and port components can only be set if the host component
185 is present. Setting these components without a host component present will have no
188 @param aData A descriptor pointer to the new value for the uri component.
189 @param aComponent An enum specifying the component to be set.
190 @pre Object is fully constructed.
191 @post The uri has the specified component set to the new value.
192 @Leave KErrArgument If aComponent goes out of range.
194 EXPORT_C void CUri8::SetComponentL(const TDesC8& aData, TUriComponent aComponent)
196 // Update the appropriate component table entry
197 iUri.iComponent[aComponent].Set(aData);
199 // Copy to the buffer by forming the uri
204 Removes the specified component from the uri. If the component does not exist then this function
207 @warning If host is removed, then userinfo and port components will also
210 @param aComponent An enum specifying the component to be removed.
211 @pre Object is fully constructed.
212 @post The uri is updated to exclude the specified component.
214 EXPORT_C void CUri8::RemoveComponentL(TUriComponent aComponent)
216 if( iUri.IsPresent(aComponent) )
218 // Remove the component - set pointer to NULL and length to zero
219 iUri.iComponent[aComponent].Set(NULL,0);
221 // Re-form buffer and component table
227 Constructor. First phase of two-phase construction method. Does non-allocating construction.
230 @param aUri The parsed uri component information from which to create
233 CUri8::CUri8(const TUriC8& aUri)
234 : CBase(), iUri(aUri)
239 Second phase of two-phase construction method. Does any allocations required to fully construct
243 @pre First phase of construction is complete.
244 @post The object is fully constructed and initialized.
246 void CUri8::ConstructL()
253 Forms the uri from the parsed uri information. A copy of the parsed uri is created. The parsed uri
254 is changed to refer to the copy.
257 @pre The parsed uri information is set.
258 @post The uri buffer is updated with the parsed uri information.
260 void CUri8::FormUriL()
264 // Calculate length of of the Uri
265 TInt length = CalculateUriLength(iUri.iComponent, isIPv6Host);
267 // Create a temporary buffer and descriptor pointer to it
268 HBufC8* buf = HBufC8::NewL(length);
269 TPtr8 uri = buf->Des();
271 // Create the uri, updating the internal uri object
272 DoFormUri(uri, iUri.iComponent, isIPv6Host);
274 // Update the internal buffer and descriptor pointer
277 iUri.iUriDes.Set(iUriBuf->Des());
282 // Implementation of CUri16
287 Static factory constructor. Uses two phase construction and leaves nothing on the CleanupStack.
288 Creates a uri object which is a copy of the input parameter aUri.
290 @deprecated Deprecated in 9.1
292 @param aUri A reference to a parsed uri object.
293 @return A pointer to the newly created CUri16 object.
294 @post A fully constructed and initialized CUri16 object.
296 EXPORT_C CUri16* CUri16::NewL(const TUriC16& aUri)
298 CUri16* self = CUri16::NewLC(aUri);
299 CleanupStack::Pop(self);
304 Static factory constructor. Uses two phase construction and leaves a pointer to created object on
305 the CleanupStack. Creates a uri object which is a copy of the input parameter aUri.
308 @deprecated Deprecated in 9.1
309 @param aUri A reference to a parsed uri object.
310 @return A pointer to the newly created CUri16 object.
311 @post A fully constructed and initialized CUri16 object.
313 EXPORT_C CUri16* CUri16::NewLC(const TUriC16& aUri)
315 CUri16* self = new (ELeave) CUri16(aUri);
316 CleanupStack::PushL(self);
322 Static factory constructor. Uses two phase construction and leaves nothing on the CleanupStack.
323 Creates a uri object which is empty.
326 @deprecated Deprecated in 9.1
327 @return A pointer to the newly created CUri16 object.
328 @post A fully constructed and initialized CUri16 object.
330 EXPORT_C CUri16* CUri16::NewL()
332 CUri16* self = CUri16::NewLC();
333 CleanupStack::Pop(self);
338 Static factory constructor. Uses two phase construction and leaves a pointer to created object on
339 the CleanupStack. Creates a uri object which is empty.
342 @deprecated Deprecated in 9.1
343 @return A pointer to the newly created CUri16 object.
344 @post A fully constructed and initialized CUri16 object.
346 EXPORT_C CUri16* CUri16::NewLC()
348 CUri16* self = new (ELeave) CUri16(TUriC16());
349 CleanupStack::PushL(self);
355 Static factory constructor. This creates a CUri16 object that is an absolute uri resulting from a
356 reference uri being resolved against a base uri.
358 @warning Ownership of created CUri16 object is transferred to caller.
359 @leave KUriErrBadBasePath if the base path is not an absolute path and not empty.
361 @deprecated Deprecated in 9.1
362 @param aBaseUri A referece to the parsed base uri.
363 @param aRefUri A referece to the parsed reference uri.
364 @return A pointer to the newly created CUri16 object.
365 @pre The base uri must have an absolute or empty path, otherwise will leave
366 with KUriErrBadBasePath.
367 @post A fully constructed and initialized CUri16 object.
369 EXPORT_C CUri16* CUri16::ResolveL(const TUriC16& aBaseUri, const TUriC16& aRefUri)
371 // Check for a base Uri
372 if( aBaseUri.UriDes().Compare(KNullDesC16) == 0 )
374 // Empty base Uri - resolved Uri is the reference Uri
375 return NewL(aRefUri);
377 // See if ref has scheme and it is the same as base Uri
378 if( aRefUri.IsPresent(EUriScheme) && aRefUri.Compare(aBaseUri, EUriScheme) != 0 )
380 // Ref has a scheme different to base Uri's - it is an absolute Uri
381 return NewL(aRefUri);
383 // Check for presence of components
384 TBool useBaseQuery = EFalse;
385 HBufC16* resolvedPath = FormResolvedPathLC<HBufC16>(aBaseUri, aRefUri, useBaseQuery);
387 // Put the Uri together
389 FormResolvedUri(uri.iComponent, aBaseUri, aRefUri, resolvedPath, useBaseQuery);
391 // Create the resolved Uri and cleanup
392 CUri16* resolvedUri = NewL(uri);
393 CleanupStack::PopAndDestroy(resolvedPath);
402 @deprecated Deprecated in 9.1
404 EXPORT_C CUri16::~CUri16()
410 Provides a reference to the parsed uri. Allows access to the non-modifying API for TUriC16.
413 @deprecated Deprecated in 9.1
414 @return A const reference to the parsed uri object.
416 EXPORT_C const TUriC16& CUri16::Uri() const
422 Sets the specified component in the uri. The component is set to the value given in the argument
423 aData. If the specified component already exists then it is replaced with the new value.
425 @warning The userinfo and port components can only be set if the host component
426 is present. Setting these components without a host component present will have no
429 @deprecated Deprecated in 9.1
430 @param aData A descriptor pointer to the new value for the uri component.
431 @param aComponent An enum specifying the component to be set.
432 @pre Object is fully constructed.
433 @post The uri has the specified component set to the new value.
434 @Leave KErrArgument If aComponent goes out of range.
436 EXPORT_C void CUri16::SetComponentL(const TDesC16& aData, TUriComponent aComponent)
438 // Update the appropriate component table entry
439 iUri.iComponent[aComponent].Set(aData);
441 // Copy to the buffer by forming the uri
446 Removes the specified component from the uri. If the component does not exist then this function
449 @warning If host is removed, then userinfo and port components will also
452 @deprecated Deprecated in 9.1
453 @param aComponent An enum specifying the component to be removed.
454 @pre Object is fully constructed.
455 @post The uri is updated to exclude the specified component.
457 EXPORT_C void CUri16::RemoveComponentL(TUriComponent aComponent)
459 if( iUri.IsPresent(aComponent) )
461 // Remove the component - set pointer to NULL and length to zero
462 iUri.iComponent[aComponent].Set(NULL,0);
464 // Re-form buffer and component table
470 Constructor. First phase of two-phase construction method. Does non-allocating construction.
473 @param aUri The parsed uri component information from which to create
477 CUri16::CUri16(const TUriC16& aUri)
478 : CBase(), iUri(aUri)
483 Second phase of two-phase construction method. Does any allocations required to fully construct
487 @pre First phase of construction is complete.
488 @post The object is fully constructed and initialized.
490 void CUri16::ConstructL()
497 Forms the uri from the parsed uri information. A copy of the parsed uri is created. The parsed uri
498 is changed to refer to the copy.
501 @pre The parsed uri information is set.
502 @post The uri buffer is updated with the parsed uri information.
504 void CUri16::FormUriL()
508 // Calculate length of of the Uri
509 TInt length = CalculateUriLength(iUri.iComponent, isIPv6Host);
511 // Create a temporary buffer and descriptor pointer to it
512 HBufC16* buf = HBufC16::NewL(length);
513 TPtr16 uri = buf->Des();
515 // Create the uri, updating the internal uri object
516 DoFormUri(uri, iUri.iComponent, isIPv6Host);
518 // Update the internal buffer and descriptor pointer
521 iUri.iUriDes.Set(iUriBuf->Des());
526 // Implementation of templated LOCAL functions
531 Calculates the length of the uri from a list of the components.
534 @param aComponent The array of descriptor pointers to the uri
536 @param aIsIPv6Host ETrue if an IPv6 format host is used
537 @return The length of the uri including the required delimiters.
539 template<class TPtrCType>
540 TInt CalculateUriLength(const TPtrCType aComponent[], TBool& aIsIPv6Host)
542 TBool noAuthority = ETrue;
545 for( TInt i=0; i<EUriMaxComponents; ++i )
547 if( aComponent[i].Ptr() )
549 length += aComponent[i].Length();
550 if( noAuthority && (i==EUriUserinfo || i==EUriHost || i==EUriPort) )
552 // There's an authority part...
553 noAuthority = EFalse;
555 // Need to make space for a delimiter if not path or host
556 if( i!=EUriHost && i!=EUriPath )
559 // If it's an IPv6 hostname, need extra space for []
560 if(i==EUriHost && (UriUtils::HostType(aComponent[i])==UriUtils::EIPv6Host))
567 if( !noAuthority && IsNetworkScheme(aComponent[EUriScheme]))
569 // Make space for authority delimiter
570 length += KUriNetworkAuthorityDelimiterLength;
576 Templated function to form a uri. The output argument aUri points to a descriptor
577 buffer large enough to hold the uri. The new uri component information is given by
578 the input/output argument aComponent. For each uri component that exists in aComponent,
579 that component and its appropriate delimiters are appended to aUri. Then the components
580 in aComponent are updated to refer to the copies versions in aUri.
583 @param aUri The descriptor pointer to buffer to be appended.
584 @param aComponent The array of descriptor pointers to be copied and
586 @param aIsIPv6Host ETrue if an IPv6 format host is used
587 @pre The buffer pointed to by aUri should be large enough to have the uri
588 components given in aNewComponent copied into it, as well as the required delimiters.
589 This can be obtained using CalculateUriLength().
590 @post The uri buffer pointed to by aUri will have a copy of the uri defined
591 in aComponent, and then aComponent will refer to the copies of these components in aUri.
593 template<class TPtrType, class TPtrCType>
594 void DoFormUri(TPtrType& aUri, TPtrCType aComponent[], TBool& aIsIPv6Host)
596 TBool isNetworkScheme = ETrue;
597 if( aComponent[EUriScheme].Ptr() )
600 SetScheme(aUri, aComponent[EUriScheme]);
601 isNetworkScheme = IsNetworkScheme(aComponent[EUriScheme]);
603 if( aComponent[EUriHost].Ptr() )
605 // Update the authority - only needed if there is a host; update userinfo, host and port
606 SetAuthority(aUri, aComponent[EUriUserinfo], aComponent[EUriHost], aComponent[EUriPort], aIsIPv6Host, isNetworkScheme);
610 // Ensure that there is no userinfo or port components if there is no host
611 // - set pointer to NULL and length to zero
612 aComponent[EUriUserinfo].Set(NULL,0);
613 aComponent[EUriPort].Set(NULL,0);
615 if( aComponent[EUriPath].Ptr() )
618 SetPath(aUri, aComponent[EUriPath]);
620 if( aComponent[EUriQuery].Ptr() )
623 SetQuery(aUri, aComponent[EUriQuery]);
625 if( aComponent[EUriFragment].Ptr() )
627 // Update the fragment
628 SetFragment(aUri, aComponent[EUriFragment]);
633 Templated function to set the scheme in a uri. The output argument aUri points to the descriptor
634 buffer into which aScheme will be copied.The argument aScheme is then updated to point to the
635 copied version in aUri.
637 @warning This function will panic with KUriErrBufferOverflow if there is not
638 enough space in the descriptor to append the scheme and the required delimiter.
640 @param aUri The descriptor pointer to buffer to be appended.
641 @param aScheme The descriptor pointer to the scheme component to be copied
643 @pre The buffer pointed to by aUri should be large enough to have aNewScheme
644 appended to it with the required delimiter. This can be obtained using CalculateUriLength().
645 @post The uri buffer now includes a copy of aScheme and aScheme points to the
646 copy of the scheme component in aUri.
648 template<class TPtrType, class TPtrCType>
649 void SetScheme(TPtrType& aUri, TPtrCType& aScheme)
651 __ASSERT_DEBUG(aUri.Length() + aScheme.Length() + 1 <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow));
653 // Append the scheme and delimiter
654 aUri.Append(aScheme);
655 aUri.Append(KSchemeDelimiter);
657 // Update the component table to use the copy
658 aScheme.Set(aUri.Left(aScheme.Length()));
662 Templated function to set the authority in a uri. The output argument aUri points to the descriptor
663 buffer into which aUserinfo, aHost and aPort will be copied. The arguments aUserinfo, aHost and aPort
664 are updated to point to the copied versions in aUri.
666 @warning This function will panic with KUriErrBufferOverflow if there
667 is not enough space in the descriptor to append the components and any required
670 @param aUri The descriptor pointer to buffer to be appended.
671 @param aUserinfo The descriptor pointer to the userinfo component to
672 be copied and then updated.
673 @param aHost The descriptor pointer to the host component to
674 be copied and then updated.
675 @param aPort The descriptor pointer to the port component to
676 be copied and then updated.
677 @param aIsIPv6Host ETrue if an IPv6 format host is used
678 @param aUseNetworkDelimiter EFalse if this is a SIP scheme otherwise ETrue
679 @pre The buffer pointed to by aUri should be large enough to have
680 aUserinfo, aHost and aPort appended to it with the required delimiters.
681 This can be obtained using CalculateUriLength().
682 @post The uri buffer now includes a copy of aUserinfo, aHost and
683 aPort, and aUserinfo, aHost and aPort will refer to the copies versions in aUri.
685 template<class TPtrType, class TPtrCType>
686 void SetAuthority(TPtrType& aUri, TPtrCType& aUserinfo, TPtrCType& aHost, TPtrCType& aPort, TBool& aIsIPv6Host, TBool aUseNetworkDelimiter)
688 __ASSERT_DEBUG(aUri.Length() + aHost.Length() + (aUseNetworkDelimiter ? KUriNetworkAuthorityDelimiterLength:0) <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow));
690 if (aUseNetworkDelimiter)
692 // If a network scheme append authority delimiter (TWO slash delimiters!)
693 aUri.Append(KSlashDelimiter);
694 aUri.Append(KSlashDelimiter);
697 // Check for userinfo
698 if( aUserinfo.Ptr() )
700 __ASSERT_DEBUG(aUri.Length() + aUserinfo.Length() + aHost.Length() + 1 <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow));
702 // Append userinfo and update the component table to use copy
703 aUri.Append(aUserinfo);
704 aUserinfo.Set(aUri.Right(aUserinfo.Length()));
707 aUri.Append(KUserinfoDelimiter);
709 // There's always a host - append and update the component table to use the copy
711 // Check if it's an IPv6 address
714 aUri.Append(KIPv6UriOpenBrace);
716 aUri.Append(KIPv6UriCloseBrace);
717 // Dont include the braces in the host
718 // Position = (length of uri - length of host) - length of end brace
719 aHost.Set( aUri.Mid((aUri.Length()-aHost.Length())-1, aHost.Length()) );
724 aHost.Set(aUri.Right(aHost.Length()));
730 __ASSERT_DEBUG(aUri.Length() + aPort.Length() + 1 <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow));
733 aUri.Append(KPortDelimiter);
735 // Append port and update the component table to use copy
737 aPort.Set(aUri.Right(aPort.Length()));
741 Templated function to set the path in a uri. The output argument aUri points to the descriptor
742 buffer into which aPath will be copied.The argument aPath is then updated to point to the copied
745 @warning This function will panic with KUriErrBufferOverflow if there
746 is not enough space in the descriptor to append the path.
748 @param aUri The descriptor pointer to buffer to be appended.
749 @param aPath The descriptor pointer to the path component to be copied
751 @pre The buffer pointed to by aUri should be large enough to have
752 aPath appended to it. This can be obtained using CalculateUriLength().
753 @post The uri buffer now includes a copy of aPath and aPath points to the
754 copy of the path component in aUri.
756 template<class TPtrType, class TPtrCType>
757 void SetPath(TPtrType& aUri, TPtrCType& aPath)
759 __ASSERT_DEBUG(aUri.Length() + aPath.Length() <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow));
764 // Update the component table
765 aPath.Set(aUri.Right(aPath.Length()));
769 Templated function to set the query in a uri. The output argument aUri points to the descriptor
770 buffer into which aQuery will be copied. The argument aQuery is then updated to point to the copied
773 @warning This function will panic with KUriErrBufferOverflow if there
774 is not enough space in the descriptor to append the query and the delimiter.
776 @param aUri The descriptor pointer to buffer to be appended.
777 @param aQuery The descriptor pointer to the query component to be copied
779 @pre The buffer pointed to by aUri should be large enough to have
780 aQuery appended to it. This can be obtained using CalculateUriLength().
781 @post The uri buffer now includes a copy of aQuery and aQuery points to the
782 copy of the query component in aUri.
784 template<class TPtrType, class TPtrCType>
785 void SetQuery(TPtrType& aUri, TPtrCType& aQuery)
787 __ASSERT_DEBUG(aUri.Length() + aQuery.Length() + 1 <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow));
789 // Append delimiter and the query
790 aUri.Append(KQueryDelimiter);
793 // Update the component table
794 aQuery.Set(aUri.Right(aQuery.Length()));
798 Templated function to set the fragment in a uri. The output argument aUri points to the descriptor
799 buffer into which aFragment will be copied. The argument aFragment is then updated to point to the
800 copied version in aUri.
802 @warning This function will panic with KUriErrBufferOverflow if there
803 is not enough space in the descriptor to append the fragment and the delimiter.
805 @param aUri The descriptor pointer to buffer to be appended.
806 @param aFragment The descriptor pointer to the fragment component
807 to be copied and then updated.
808 @pre The buffer pointed to by aUri should be large enough to have
809 aFragment appended to it. This can be obtained using CalculateUriLength().
810 @post The uri buffer now includes a copy of aFragment and aFragment points
811 to the copy of the fragment component in aUri.
813 template<class TPtrType, class TPtrCType>
814 void SetFragment(TPtrType& aUri, TPtrCType& aFragment)
816 __ASSERT_DEBUG(aUri.Length() + aFragment.Length() + 1 <= aUri.MaxLength(), User::Panic(KUriPanicCategory, KUriUtilsErrBufferOverflow));
818 // Append delimiter and the fragment
819 aUri.Append(KFragmentDelimiter);
820 aUri.Append(aFragment);
822 // Update the component table
823 aFragment.Set(aUri.Right(aFragment.Length()));
827 Forms the resolved path. Checks to see if the base query needs to be used in the resolved uri.
828 The pointer to the resolved path is left on the cleanup stack.
831 @param aBaseUri The base uri.
832 @param aRefUri The reference uri.
833 @param aUseBaseQuery An output argument specifying whether the base
834 query should be used in the resolved uri.
835 @return A pointer to a buffer that contains the resolved path.
837 template<class HBufCType, class TUriCType>
838 HBufCType* FormResolvedPathLC(const TUriCType& aBaseUri, const TUriCType& aRefUri, TBool& aUseBaseQuery)
840 HBufCType* resolvedPath = NULL;
841 if( !aRefUri.IsPresent(EUriScheme) && !aRefUri.IsPresent(EUriHost) && !aRefUri.Extract(EUriPath).Length() && !aRefUri.IsPresent(EUriQuery) )
843 // Ref is just a fragment
844 aUseBaseQuery = ETrue;
845 resolvedPath = aBaseUri.Extract(EUriPath).AllocLC();
847 else if( aRefUri.IsPresent(EUriHost) )
849 // Ref is a network path
850 resolvedPath = aRefUri.Extract(EUriPath).AllocLC();
854 // Need to some path resolving...
855 resolvedPath = ResolvePathsL(aBaseUri.Extract(EUriPath), aRefUri.Extract(EUriPath));
856 CleanupStack::PushL(resolvedPath);
862 Cleans up a resolved path. This deals with occurences of '.' and '..' where these are complete
866 @param aResolvedPath The delimited data object that contains the
868 @pre The input/output argument contains the path to be cleaned.
869 @post The resolved path has had all the occurences of '.' and '..'
870 processed and has been updated to contain the cleaned path.
872 template<class TPtrCType, class CDelimitedDataBaseType>
873 void CleanResolvedPathL(CDelimitedDataBaseType* aResolvedPath)
875 // Create a modifiable path object for resolved path
876 aResolvedPath->Parse();
881 // Get the next segment
883 TInt more = aResolvedPath->Parser().Peek(segment);
885 if( more == KErrNotFound )
887 // No more segments - done
890 else if( IsParentDir(segment) )
892 // Found a '..' - remove '..' from path, and remove previous segment
893 aResolvedPath->RemoveCurrentL();
894 if( aResolvedPath->Parser().Dec() == KErrNotFound )
896 // No previous directory - put back '..' and stop
897 InsertParentDirL(aResolvedPath);
902 // Remove the parent directory
903 aResolvedPath->RemoveCurrentL();
904 if( aResolvedPath->Parser().Eos() )
906 // '..' is the last segment - add a '/' to the path (add empty segment)
907 aResolvedPath->AddBackDelimiterL();
912 else if( IsSameDir(segment) )
914 // Found a '.' - remove -.- from the path
915 aResolvedPath->RemoveCurrentL();
916 if( aResolvedPath->Parser().Eos() )
918 // '..' is the last segment - add a '/' to the path (add empty segment)
919 aResolvedPath->AddBackDelimiterL();
925 // Segment wasn't '.' or '..' - parse to next segment
926 aResolvedPath->Parser().Inc();
932 Forms the resolved uri. Sets the components for the resolved uri from those in the base uri and
933 the reference uri. The resolved path is given by the input argument aResolvedPath
936 @param aComponent The array of components to be set for the resolved uri.
937 @param aBaseUri The base uri.
938 @param aRefUri The reference uri.
939 @param aResolvedPath The resolved path.
940 @param aUseBaseQuery A boolean indicating whether the base query
943 template<class TPtrCType, class TUriCType, class HBufCType>
944 void FormResolvedUri(TPtrCType aComponent[], const TUriCType& aBaseUri, const TUriCType& aRefUri, const HBufCType* aResolvedPath, TBool aUseBaseQuery)
947 if( aBaseUri.IsPresent(EUriScheme) )
949 // Use the base scheme
950 aComponent[EUriScheme].Set(aBaseUri.Extract(EUriScheme));
953 if( aRefUri.IsPresent(EUriHost) )
955 // Use the ref host, userinfo and port - must set host first
956 aComponent[EUriHost].Set(aRefUri.Extract(EUriHost));
957 aComponent[EUriUserinfo].Set(aRefUri.Extract(EUriUserinfo));
958 aComponent[EUriPort].Set(aRefUri.Extract(EUriPort));
960 else if( aBaseUri.IsPresent(EUriHost) )
962 // Use the base host, userinfo and port - must set host first
963 aComponent[EUriHost].Set(aBaseUri.Extract(EUriHost));
964 aComponent[EUriUserinfo].Set(aBaseUri.Extract(EUriUserinfo));
965 aComponent[EUriPort].Set(aBaseUri.Extract(EUriPort));
968 aComponent[EUriPath].Set(*aResolvedPath);
971 if( aUseBaseQuery && aBaseUri.IsPresent(EUriQuery) )
973 // Use the query from the base
974 aComponent[EUriQuery].Set(aBaseUri.Extract(EUriQuery));
976 else if( aRefUri.IsPresent(EUriQuery) )
978 // Use the query from the ref
979 aComponent[EUriQuery].Set(aRefUri.Extract(EUriQuery));
982 if( aRefUri.IsPresent(EUriFragment) )
984 // Use the fragment from the ref
985 aComponent[EUriFragment].Set(aRefUri.Extract(EUriFragment));
991 // Implemetation of LOCAL functions
996 Function used to resolve a base path (aBasePath) against a reference path (aRefPath),
997 as described by RFC2396.
1000 @param aBasePath A descriptor reference to the base path.
1001 @param aRefPath A descriptor reference to the reference path.
1002 @return A pointer to a buffer containing the resolve path.
1003 @leave KUriErrBadBasePath if the base path is not an absolute path and not empty.
1005 HBufC8* ResolvePathsL(const TDesC8& aBasePath, const TDesC8& aRefPath)
1007 TInt refLength = aRefPath.Length();
1008 if( refLength && aRefPath[0] == KSlashDelimiter )
1010 // Relative path is absolute - that is the resolved path
1011 return aRefPath.AllocL();
1013 // Ok got work to do - base path must be absolute (check 1st char) or empty
1014 if( aBasePath.Length() && aBasePath[0] != KSlashDelimiter )
1016 // Base path not empty and not abosolute - bad base path
1017 User::Leave(KUriUtilsErrBadBasePath);
1019 // Create a modifiable path object for resolved path
1020 CDelimitedPath8* resolvedPath = CDelimitedPath8::NewLC(aBasePath);
1022 // Check for empty ref path - use all of base path if empty
1025 // Not empty - ensure that base path's last segment is removed and add reference
1026 resolvedPath->PopBackL();
1027 resolvedPath->PushBackL(aRefPath);
1029 // Clean up the path to resolve occurences of '..' and '.' - parser path first
1030 CleanResolvedPathL<TPtrC8>(resolvedPath);
1032 // Return pointer to HBufC with path
1033 HBufC8* path = resolvedPath->Parser().Des().AllocL();
1034 CleanupStack::PopAndDestroy(resolvedPath);
1039 Function used to resolve a base path (aBasePath) against a reference path (aRefPath),
1040 as described by RFC2396.
1043 @param aBasePath A descriptor reference to the base path.
1044 @param aRefPath A descriptor reference to the reference path.
1045 @return A pointer to a buffer containing the resolve path.
1046 @leave KUriErrBadBasePath if the base path is not an absolute path and not empty.
1048 HBufC16* ResolvePathsL(const TDesC16& aBasePath, const TDesC16& aRefPath)
1050 TInt refLength = aRefPath.Length();
1051 if( refLength && aRefPath[0] == KSlashDelimiter )
1053 // Relative path is absolute - that is the resolved path
1054 return aRefPath.AllocL();
1056 // Ok got work to do - base path must be absolute (check 1st char) or empty
1057 if( aBasePath.Length() && aBasePath[0] != KSlashDelimiter )
1059 // Base path not empty and not abosolute - bad base path
1060 User::Leave(KUriUtilsErrBadBasePath);
1062 // Create a modifiable path object for resolved path
1063 CDelimitedPath16* resolvedPath = CDelimitedPath16::NewLC(aBasePath);
1065 // Check for empty ref path - use all of base path if empty
1068 // Not empty - ensure that base path's last segment is removed and add reference
1069 resolvedPath->PopBackL();
1070 resolvedPath->PushBackL(aRefPath);
1072 // Clean up the path to resolve occurences of '..' and '.' - parser path first
1073 CleanResolvedPathL<TPtrC16>(resolvedPath);
1075 // Return pointer to HBufC with path
1076 HBufC16* path = resolvedPath->Parser().Des().AllocL();
1077 CleanupStack::PopAndDestroy(resolvedPath);
1082 Checks if the segment is '.' (8-bit version).
1085 @param aSegment A descriptor with the segment to check.
1086 @return A boolean value of ETrue if the segment is '.', EFalse if not.
1088 TBool IsSameDir(const TDesC8& aSegment)
1090 _LIT8(KSameDir, ".");
1091 return (aSegment.Compare(KSameDir) == 0);
1095 Checks if the segment is '.' (16-bit version).
1098 @param aSegment A descriptor with the segment to check.
1099 @return A boolean value of ETrue if the segment is '.', EFalse if not.
1101 TBool IsSameDir(const TDesC16& aSegment)
1103 _LIT16(KSameDir, ".");
1104 return (aSegment.Compare(KSameDir) == 0);
1108 Checks if the segment is '..' (8-bit version).
1111 @param aSegment A descriptor with the segment to check.
1112 @return A boolean value of ETrue if the segment is '..', EFalse if not.
1114 TBool IsParentDir(const TDesC8& aSegment)
1116 _LIT8(KParentDir, "..");
1117 return (aSegment.Compare(KParentDir) == 0);
1121 Checks if the segment is '..' (16-bit version).
1124 @param aSegment A descriptor with the segment to check.
1125 @return A boolean value of ETrue if the segment is '..', EFalse if not.
1127 TBool IsParentDir(const TDesC16& aSegment)
1129 _LIT16(KParentDir, "..");
1130 return (aSegment.Compare(KParentDir) == 0);
1134 Inserts the segment '..' at the current parsed position (8-bit version).
1137 @param aResolvedPath The delimited data object to have the segment
1139 @pre The delimited data object must be parsed to the position where
1140 the segment is to be inserted.
1141 @post The segment '..' has been inserted at the current position.
1143 void InsertParentDirL(CDelimitedDataBase8* aResolvedPath)
1145 _LIT8(KParentDir, "..");
1146 aResolvedPath->InsertCurrentL(KParentDir);
1150 Inserts the segment '..' at the current parsed position (16-bit version).
1153 @param aResolvedPath The delimited data object to have the segment
1155 @pre The delimited data object must be parsed to the position where
1156 the segment is to be inserted.
1157 @post The segment '..' has been inserted at the current position.
1159 void InsertParentDirL(CDelimitedDataBase16* aResolvedPath)
1161 _LIT16(KParentDir, "..");
1162 aResolvedPath->InsertCurrentL(KParentDir);
1168 // File URI Implementation - CUri8
1173 Initializes the file URI components (scheme, empty hostname and path).
1175 It uses GenerateFileUriPathL() to generate a file Uri path using the filename and drive.
1178 @param aFileName A reference to a filename
1179 @param aDrive A drive number. This is a TFileUriFlags value.
1180 @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive.
1181 This is a TFileUriFlags value.
1182 @pre Object fully constructed
1183 @post The object is initialized with file URI components.
1185 void CUri8::InitializeFileUriComponentsL(const TDesC& aFileName, TDriveNumber aDrive, TUint aFlags)
1187 HBufC* uriPath16 = GenerateFileUriPathL(aFileName, aDrive, aFlags);
1188 CleanupStack::PushL(uriPath16);
1189 HBufC8* uriPath = EscapeUtils::ConvertFromUnicodeToUtf8L(*uriPath16);
1190 CleanupStack::PopAndDestroy(uriPath16);
1191 CleanupStack::PushL(uriPath);
1192 HBufC8* escpedUriPath = EscapeUtils::EscapeEncodeL(*uriPath, EscapeUtils::EEscapeNormal);
1193 CleanupStack::PopAndDestroy(uriPath);
1194 CleanupStack::PushL(escpedUriPath);
1196 //SetComponent is not used in order to increase efficiency, by avoiding overhead of length calculation,
1197 //tmp buffer allocation and updation of internal uri object, internal buffer & descriptor pointer
1198 //for each SetComponent call
1199 iUri.iComponent[EUriPath].Set(*escpedUriPath);
1200 iUri.iComponent[EUriHost].Set(KNullDesC8);
1201 iUri.iComponent[EUriScheme].Set(KFileUriScheme8);
1204 CleanupStack::PopAndDestroy(escpedUriPath);
1208 Allocates and constructs a file URI object for a specified file.
1210 - If the file exists on a fixed drive, then the file URI takes the form: 'file://\<drive-letter\>/\<filepath including filename\>'.
1211 - If the file exists on a removable media drive, then the file URI takes the form: 'file://ext-media/\<filepath including filename\>'.
1214 @param aFullFileName A reference to a fully qualified filename
1215 @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive.
1216 This is a TFileUriFlags value.
1217 @return A pointer to the newly created file URI (CUri8) object.
1218 @post A fully constructed and initialized file URI (CUri8) object.
1220 EXPORT_C CUri8* CUri8::CreateFileUriL(const TDesC& aFullFileName, TUint aFlags)
1222 //It should be called to construct a file URI for a public file stored on a fix drive
1223 // or on a removable media drive only
1224 __ASSERT_ALWAYS( ((aFlags == 0) || (aFlags & EExtMedia)), User::Panic(KFileUriPanicCategory, KUriUtilsCannotConvert) );
1226 CUri8* self = CUri8::NewLC();
1227 self->InitializeFileUriComponentsL(aFullFileName, EDriveA, aFlags);
1228 CleanupStack::Pop(self);
1233 Allocates and constructs a file URI object for a file that is private to the application.
1235 - If the file exists on a fixed drive, then the file URI takes the form 'file://private/\<drive-letter\>/<filepath including filename\>'.
1236 - If the file exists on a removable media drive, then the file URI takes the form 'file://private/ext-media/\<filepath including filename\>'.
1239 @param aRelativeFileName A reference to the filename relative to the application's private directory.
1240 @param aDrive Drive number, if the private file stored on fixed drive, otherwise not used
1241 This is a TDriveNumber value
1242 @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive.
1243 This is a TFileUriFlags value.
1244 @return A pointer to the newly created file URI (CUri8) object.
1245 @post A fully constructed and initialized file URI (CUri8) object.
1249 EXPORT_C CUri8* CUri8::CreatePrivateFileUriL(const TDesC& aRelativeFileName, TDriveNumber aDrive, TInt aFlags)
1251 //It should be called to construct a file URI for the application's private file stored on a fix drive
1252 // or on a removable media drive only
1253 __ASSERT_ALWAYS( (((aFlags == 0) || (aFlags & EExtMedia)) && (aDrive >= EDriveA && aDrive <= EDriveZ)), User::Panic(KFileUriPanicCategory, KUriUtilsCannotConvert) );
1255 CUri8* self = CUri8::NewLC();
1256 self->InitializeFileUriComponentsL(aRelativeFileName, aDrive, aFlags|EPrivate);
1257 CleanupStack::Pop(self);
1264 // File URI Implementation - CUri16
1269 Initializes the file URI components (scheme, empty hostname and path).
1271 It uses GenerateFileUriPathL() to generate a file Uri path using the filename and drive.
1274 @param aFileName A reference to a filename
1275 @param aDrive A drive number. This is a TFileUriFlags value.
1276 @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive.
1277 This is a TFileUriFlags value.
1278 @pre Object fully constructed
1279 @post The object is initialized with file URI components.
1281 void CUri16::InitializeFileUriComponentsL(const TDesC& aFileName, TDriveNumber aDrive, TUint aFlags)
1283 HBufC* uriPath = GenerateFileUriPathL(aFileName, aDrive, aFlags);
1284 CleanupStack::PushL(uriPath);
1286 HBufC8* uriPath8 = EscapeUtils::ConvertFromUnicodeToUtf8L(*uriPath);
1287 CleanupStack::PopAndDestroy(uriPath);
1288 CleanupStack::PushL(uriPath8);
1290 HBufC8* escapedUriPath8 = EscapeUtils::EscapeEncodeL(*uriPath8, EscapeUtils::EEscapeNormal);
1291 CleanupStack::PopAndDestroy(uriPath8);
1292 CleanupStack::PushL(escapedUriPath8);
1294 HBufC* escapedUriPath = HBufC::NewLC(escapedUriPath8->Length());
1295 escapedUriPath->Des().Copy(*escapedUriPath8);
1297 //SetComponent is not used in order to increase efficiency, by avoiding overhead of length calculation,
1298 //tmp buffer allocation and updation of internal uri object, internal buffer & descriptor pointer
1299 //for each SetComponent call
1300 iUri.iComponent[EUriPath].Set(*escapedUriPath);
1301 iUri.iComponent[EUriHost].Set(KNullDesC16);
1302 iUri.iComponent[EUriScheme].Set(KFileUriScheme16);
1305 CleanupStack::PopAndDestroy(escapedUriPath);
1306 CleanupStack::PopAndDestroy(escapedUriPath8);
1310 Allocates and constructs a file URI object for a specified file.
1312 - If the file exists on a fixed drive, then the file URI takes the form: 'file://\<drive-letter\>/\<filepath including filename\>'.
1313 - If the file exists on a removable media drive, then the file URI takes the form: 'file://ext-media/\<filepath including filename\>'.
1316 @param aFullFileName A reference to a fully qualified filename
1317 @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive.
1318 This is a TFileUriFlags value.
1319 @return A pointer to the newly created file URI (CUri16) object.
1320 @post A fully constructed and initialized file URI (CUri16) object.
1322 EXPORT_C CUri16* CUri16::CreateFileUriL(const TDesC& aFullFileName, TUint aFlags)
1324 //It should be called to construct a file URI for a public file stored on a fix drive
1325 // or on a removable media drive only
1326 __ASSERT_ALWAYS( ((aFlags == 0) || (aFlags & EExtMedia)), User::Panic(KFileUriPanicCategory, KUriUtilsCannotConvert) );
1328 CUri16* self = CUri16::NewLC();
1329 self->InitializeFileUriComponentsL(aFullFileName, EDriveA, aFlags);
1330 CleanupStack::Pop(self);
1335 Allocates and constructs a file URI object for a file that is private to the application.
1337 - If the file exists on a fixed drive, then the file URI takes the form 'file://private/\<drive-letter\>/<filepath including filename\>'.
1338 - If the file exists on a removable media drive, then the file URI takes the form 'file://private/ext-media/\<filepath including filename\>'.
1341 @param aRelativeFileName A reference to the filename relative to the application's private directory.
1342 @param aDrive Drive number, if the private file stored on fixed drive, otherwise not used
1343 This is a TDriveNumber value
1344 @param aFlags A flag to indicate if the file exists on a fixed drive or removable media drive.
1345 This is a TFileUriFlags value.
1346 @return A pointer to the newly created file URI (CUri16) object.
1347 @post A fully constructed and initialized file URI (CUri16) object.
1351 EXPORT_C CUri16* CUri16::CreatePrivateFileUriL(const TDesC& aRelativeFileName, TDriveNumber aDrive, TInt aFlags)
1353 //It should be called to construct a file URI for the application's private file stored on a fix drive
1354 // or on a removable media drive only
1355 __ASSERT_ALWAYS( (((aFlags == 0) || (aFlags & EExtMedia)) && (aDrive >= EDriveA && aDrive <= EDriveZ)), User::Panic(KFileUriPanicCategory, KUriUtilsCannotConvert) );
1357 CUri16* self = CUri16::NewLC();
1358 self->InitializeFileUriComponentsL(aRelativeFileName, aDrive, aFlags|EPrivate);
1359 CleanupStack::Pop(self);
1366 // Implemetation of LOCAL functions for the File URI
1371 Function used to generate 16bit file uri using 1st parameter aFileName and
1372 2nd parameter aDrive for the application's private or a public file.
1374 This is called by API CreateFileUri() and CreatePrivateFileUri()to
1375 generate a filename.
1377 Note: The space allocated for the returned descriptor will likely be larger
1378 than the length of the descriptor
1380 @leave KErrBadName A provided Drivename or filename is not valid
1382 @param aFileName A descriptor reference to the filename.
1383 @param aDrive A descriptor reference to drive letter.
1384 @param aFlags A flag to indicate the private or a public file exists on removable media or a fixed drive.
1385 @return A pointer to a buffer containing the resolved fully qualified filename.
1387 HBufC* GenerateFileUriPathL(const TDesC& aFileName, TDriveNumber aDrive, TUint aFlags)
1389 TInt origLength = aFileName.Length();
1391 //Leaves with KErrBadName if filename length is out of range
1392 if (origLength == 0 || origLength > KMaxFileName)
1394 User::Leave(KErrBadName);
1397 TPtrC filename(aFileName);
1399 //extract drive letter and remove drive "x:" from filename
1400 TUint drive = filename[0];
1402 // hasDrive means it begins with a drive, e.g. "c:"
1403 const TBool hasDrive = ((drive >= 'A' && drive <= 'Z') || (drive >= 'a' && drive <= 'z')) && (filename[1] == KDriveSeparator);
1404 // hasTopPath means it begins with a \ (possibly after the drive)
1405 const TBool hasTopPath = (hasDrive && (filename[2] == KFilePathSeparator)) || (!hasDrive && (drive == TUint(KFilePathSeparator) ));
1407 TInt skip = KDefaultPath().Length(); // skip leading "<drive>:\" by default
1408 if(aFlags & TUint(EPrivate))
1410 skip = (hasDrive ? (KDefaultPath().Length() - 1) : 0) + (hasTopPath ? 1 : 0) ;
1414 // if not private then it should have valid drive i.e. "<drive>:\"
1415 if (!(hasDrive && hasTopPath))
1417 User::Leave(KErrBadName);
1423 filename.Set(aFileName.Right(origLength - skip));
1426 TInt uriLen = aFileName.Length() + KExtMedia().Length() + KPrivate().Length() + 1 /* for drive letter */;
1428 HBufC* fileUri = HBufC::NewLC(uriLen);
1429 TPtr fileUriPtr = fileUri->Des();
1430 fileUriPtr.Append(KUriPathSeparator);
1432 if (aFlags & TUint(EPrivate))
1434 fileUriPtr.Append(KPrivate);
1435 drive = TInt16('A' + aDrive);
1438 if (aFlags & EExtMedia)
1440 fileUriPtr.Append(KExtMedia);
1444 fileUriPtr.Append(drive);
1445 fileUriPtr.Append(KUriPathSeparator);
1448 fileUriPtr.Append(filename);
1450 //Convert "\" to "/"
1451 ChangePathSeparator(fileUriPtr, KFilePathSeparator, KUriPathSeparator);
1453 //Handling "./" and "../" in the file URI path or resolving the URI path
1454 CDelimitedPath16* resolvedPath = CDelimitedPath16::NewLC(fileUriPtr);
1455 // Clean up the path to resolve occurences of '..' and '.'
1456 CleanResolvedPathL<TPtrC>(resolvedPath);
1457 fileUriPtr.Copy(resolvedPath->Parser().Des()); // new path will always be shorter than old one
1458 CleanupStack::PopAndDestroy(resolvedPath);
1460 CleanupStack::Pop(fileUri);