landmarks/locationlandmarks/converter/src/epos_cposlmurlencoder.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 31 Mar 2010 22:18:21 +0300
branchRCL_3
changeset 16 6fcbaa43369c
parent 0 667063e416a2
permissions -rw-r--r--
Revision: 201011 Kit: 201013

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Class used for encoding landmark content into an URL.
*
*
*/


#include    <lbsposition.h>
#include    <uri8.h>
#include    <EPos_LandmarksErrors.h>
#include    "epos_cposlmurlencoder.h"
#include    "EPos_CPosLmFileOutput.h"
#include    "EPos_CPosLmBufferOutput.h"
#include    "epos_cposlmurlencoderoperation.h"
#include    "EPos_PosLmConverterUtils.h"
#include    "EPos_CPosLmCategoryManager.h"
#include    "EPos_CPosLandmarkDatabase.h"


const TInt KPosBufferExpandSize = 600;
const TInt KRealPoint = 46;
const TInt KRealDecimalPlaces = 2;
const TInt KCoordinateDecimalPlaces = 6;
const TInt KSpecialCharacterAsciiLowerLimit1 = 32;
const TInt KSpecialCharacterAsciiUpperLimit1 = 47;
const TInt KSpecialCharacterAsciiLowerLimit2 = 58;
const TInt KSpecialCharacterAsciiUpperLimit2 = 64;
const TInt KSpecialCharacterAsciiLowerLimit3 = 91;
const TInt KSpecialCharacterAsciiUpperLimit3 = 96;
const TInt KSpecialCharacterAsciiLowerLimit4 = 123;
const TInt KSpecialCharacterAsciiUpperLimit4 = 126;


// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::CPosLmUrlEncoder
// Default Constructor
//-----------------------------------------------------------------------------
//
CPosLmUrlEncoder::CPosLmUrlEncoder()
    {
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::NewL
// -----------------------------------------------------------------------------
//
CPosLmUrlEncoder* CPosLmUrlEncoder::NewL()
    {
    return new (ELeave) CPosLmUrlEncoder;
    }
// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::~CPosLmUrlEncoder 
// Destructor
//-----------------------------------------------------------------------------
//
CPosLmUrlEncoder::~CPosLmUrlEncoder()
    {
    delete iOutput;
    iOutput = NULL;
    
    delete iLastLandmark;
    iLastLandmark = NULL;
    
    iCategories.ResetAndDestroy();
    }

//-----------------------------------------------------------------------------
// CPosLmUrlEncoder::SetUseOutputBufferL
//-----------------------------------------------------------------------------
//
CBufBase* CPosLmUrlEncoder::SetUseOutputBufferL()
    {
    // The encoder is reset before starting a new encoding process
    ResetEncoderL();
    // create an instance of the CPosLmBufferOutput 
    CPosLmBufferOutput* output = CPosLmBufferOutput::NewL(KPosBufferExpandSize);
    CleanupStack::PushL( output );
    // Assign the buffer output instance to the member variable
    iOutput = output;
       
    // Create the buffer into which the encoded output will be written
    CBufBase* buffer = output->BufferLC();
      
    // Initialize the encoding by writing the Url scheme & host
    InitializeEncodingL();

    CleanupStack::Pop( 2,output );
   
    return buffer;
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::SetOutputFileL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::SetOutputFileL(
    const TDesC& aOutputFile)
    {
    // The encoder is reset before starting a new encoding process
    ResetEncoderL();
    // Create an instance of the CPosLmFileOutput
    iOutput = CPosLmFileOutput::NewL(aOutputFile);
    // Initialize the encoding by writing the Url scheme & host
    InitializeEncodingL();
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::AddCollectionDataL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::AddCollectionDataL(
    TPosLmCollectionDataId /*aDataId*/,
    const TDesC& /*aCollectionData*/)
    {
    // Do Nothing,as URl format does not support collection data
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::AddLandmarkL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::AddLandmarkL( const CPosLandmark& aLandmark )
    {
    // Check that the encoder status is EPosInitialized when this method is called,
    // if not panic with EPosLmProtocolBreak
    __ASSERT_ALWAYS( iEncoderStatus == EPosInitialized,
            Panic( KPosLandmarksClientPanic, EPosLmProtocolBreak ) );
    
    // Check if landmark already exists,if yes then return KErrNotSupported
    // as multiple landmarks encoding is not supported.
    if ( iLastLandmark )
        {
        User::Leave( KErrNotSupported );
        }
    else
        {
        iLastLandmark = CPosLandmark::NewL( aLandmark );
        }
    
    // Encode the landmark
    EncodeLandmarkL();
    
    // Set encoder status after landamrk is added
    iEncoderStatus = EPosLmInfoAdded;
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::AddCategoryForLatestLandmarkL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::AddCategoryForLatestLandmarkL( const CPosLandmarkCategory& aCategory )
    {
    // Check that landmark is already added before adding a category,if not panic
    // with EPosLmProtocolBreak
    __ASSERT_ALWAYS(
            iEncoderStatus == EPosLmInfoAdded,
            Panic(KPosLandmarksClientPanic, EPosLmProtocolBreak));
    // Append the category information to the category array associated 
    // with the landmark to be encoded
    
    User::LeaveIfError( iCategories.Append( CPosLandmarkCategory::NewL( aCategory ) ) );
    
    
    // Encode the category and write it to the encoded output
    EncodeCategoryL();
      
    
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::InitializeEncodingL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::InitializeEncodingL()
    {
    // Write the URL scheme
    WriteUrlSchemeL();
    // Write the URL hostname
    WriteUrlHostL();
    
    // Set encoder status to  EPosInitialized
    iEncoderStatus = EPosInitialized;
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::FinalizeEncodingL
// -----------------------------------------------------------------------------
//
CPosLmOperation* CPosLmUrlEncoder::FinalizeEncodingL()
    {
    // Check that the enocder status is EPosLmInfoAdded when this method is called,
    // if not panic with EPosLmProtocolBreak
    __ASSERT_ALWAYS(
            iEncoderStatus == EPosLmInfoAdded,
            Panic(KPosLandmarksClientPanic, EPosLmProtocolBreak));
    // Create an instance of the CPosLmUrlEncoderOperation,which will be returned
    // to the client,using which the client can call ExecuteL or NextStep to execute 
    // and complete the encoding operation.
    CPosLmUrlEncoderOperation* op = CPosLmUrlEncoderOperation::NewL( iOutput );
    // Ownership of iOutput has been transferred to op.
    iOutput = NULL;
    // Change staus back to EPosUninitialized for next encoding process
    iEncoderStatus = EPosUninitialized;
    return op;
    }


// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::ResetEncoderL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::ResetEncoderL()
    {
    // Delete all previous data
    delete iOutput;
    iOutput = NULL;
       
    delete iLastLandmark;
    iLastLandmark = NULL;
   
    iCategories.ResetAndDestroy(); 
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::WriteUrlSchemeL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::WriteUrlSchemeL()
    {
    CUri8* uri = CUri8::NewL();
    CleanupStack::PushL(uri);
    // Setting URI scheme component
    uri->SetComponentL(KUrlSchemeHttp, EUriScheme);
    const TDesC8& uriBuffer = uri->Uri().UriDes();
    
    // Convert retrieved uri descriptor to HBufC16
    HBufC16* uriScheme = HBufC16::NewL( uriBuffer.Length() );
    CleanupStack::PushL( uriScheme );
    uriScheme->Des().Copy( uriBuffer ); 
    
    
    // Write the URL scheme to encoded output
    iOutput->WriteL( *uriScheme );
    CleanupStack::PopAndDestroy( 2,uri );
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::WriteUrlHostL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::WriteUrlHostL()
    {
    CUri8* uri = CUri8::NewL();
    CleanupStack::PushL(uri);
    // Setting URI host component
    uri->SetComponentL(KUrlHostFull, EUriHost);
    const TDesC8& uriBuffer = uri->Uri().UriDes();
    
    // Convert retrieved uri descriptor to HBufC16
    HBufC16* uriHost = HBufC16::NewL( uriBuffer.Length() );
    CleanupStack::PushL( uriHost );
    uriHost->Des().Copy( uriBuffer );    
    
    // Write the URL host to encoded output
    iOutput->WriteL( *uriHost );
    CleanupStack::PopAndDestroy( 2,uri );
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::EncodeLandmarkL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::EncodeLandmarkL()
    {
    // Holds value of extracted landmark text fields
    TPtrC textField;
    // Write the Url query start string 
    iOutput->WriteL( KUrlQueryStart );
    
    // Get each of the landmark attributes and encode to Url
    
    // Holds coordinate information
    TLocality position;
    // Get landmark coordinate and
    // Write landmark coordinates to the buffer only if the latitude
    // and longitude values are not NaN,else leave with KErrArgument
    if ( iLastLandmark->GetPosition( position ))
        {
        User::Leave( KErrArgument );
        }
    WriteCoordinatesL( position );
    
    
    // Get Place id
    
    if( !( iLastLandmark->GetPlaceId( textField ) ) )
        {
        HBufC* encodedPid = EncodeTextL( textField,KUrlMaxTextEncodingLength);
        CleanupStack::PushL( encodedPid );
        WriteQueryParamValueL( KUrlPidParam, *encodedPid );
        CleanupStack::PopAndDestroy( encodedPid );
        }
    
    // Get Landmark name
    if( !( iLastLandmark->GetLandmarkName( textField ) ) )
        {
        HBufC* encodedName = EncodeTextL( textField,KUrlMaxTextEncodingLength );
        CleanupStack::PushL( encodedName );
        WriteQueryParamValueL( KUrlNameParam,*encodedName );
        CleanupStack::PopAndDestroy( encodedName );
        }
    
    // Get Landmark Description
    if( !( iLastLandmark->GetLandmarkDescription( textField ) ) )
        {
        HBufC* encodedDescription = EncodeTextL( textField,KUrlMaxDescriptionEncodingLength );
        CleanupStack::PushL( encodedDescription );
        WriteQueryParamValueL( KUrlDescriptionParam,*encodedDescription );
        CleanupStack::PopAndDestroy( encodedDescription );                        
        }
    
    // Get House Number
    if( !( iLastLandmark->GetPositionField( EPositionFieldStreetExtension,textField ) ) )
        
        {
        HBufC* encodedHouseNumber = EncodeTextL( textField,KUrlMaxTextEncodingLength );
        CleanupStack::PushL( encodedHouseNumber );
        WriteQueryParamValueL( KUrlHouseNumberParam,*encodedHouseNumber );        
        CleanupStack::PopAndDestroy( encodedHouseNumber );
        }
        
    // Get Street
    if( !( iLastLandmark->GetPositionField( EPositionFieldStreet,textField ) ) )
        {
        HBufC* encodedStreet = EncodeTextL( textField,KUrlMaxTextEncodingLength );
        CleanupStack::PushL( encodedStreet );
        WriteQueryParamValueL( KUrlStreetParam,*encodedStreet );        
        CleanupStack::PopAndDestroy( encodedStreet );
        }    
        
    // Get City
    if( !( iLastLandmark->GetPositionField( EPositionFieldCity,textField ) ) )
        {
        HBufC* encodedCity = EncodeTextL( textField,KUrlMaxTextEncodingLength );
        CleanupStack::PushL( encodedCity );
        WriteQueryParamValueL( KUrlCityParam,*encodedCity );        
        CleanupStack::PopAndDestroy( encodedCity );
        }    
        
    // Get State
    if( !( iLastLandmark->GetPositionField( EPositionFieldState,textField ) ) )
       {
       HBufC* encodedState = EncodeTextL( textField,KUrlMaxTextEncodingLength );
       CleanupStack::PushL( encodedState );
       WriteQueryParamValueL( KUrlStateParam,*encodedState );        
       CleanupStack::PopAndDestroy( encodedState );
       }
       
   // Get Country
   if( !( iLastLandmark->GetPositionField( EPositionFieldCountry,textField ) ) )
       {
       HBufC* encodedCountry = EncodeTextL( textField,KUrlMaxTextEncodingLength );
       CleanupStack::PushL( encodedCountry );
       WriteQueryParamValueL( KUrlCountryParam,*encodedCountry );        
       CleanupStack::PopAndDestroy( encodedCountry );
       }
   
   // Get Postal Code
   if( !( iLastLandmark->GetPositionField( EPositionFieldPostalCode,textField ) ) )
       {
       HBufC* encodedPostalcode = EncodeTextL( textField,KUrlMaxTextEncodingLength );
       CleanupStack::PushL( encodedPostalcode );
       WriteQueryParamValueL( KUrlPostalCodeParam,*encodedPostalcode );        
       CleanupStack::PopAndDestroy( encodedPostalcode );
       }
   
   // Get Telephone
   if( !( iLastLandmark->GetPositionField( EPositionFieldBuildingTelephone,textField ) ) )
       {
       HBufC* encodedTelephone = EncodeTextL( textField,KUrlMaxTextEncodingLength );
       CleanupStack::PushL( encodedTelephone );
       WriteQueryParamValueL( KUrlTelephoneParam,*encodedTelephone );        
       CleanupStack::PopAndDestroy( encodedTelephone );
       }
   
   // Use TRealFormat to format the real number obtained for speed & heading to display
   // upto 2 decimal digits.
   TRealFormat realFormat;
   realFormat.iPoint = KRealPoint;
   realFormat.iType = KRealFormatFixed | KDoNotUseTriads;
   realFormat.iPlaces = KRealDecimalPlaces;
   realFormat.iWidth = KRealWidth;
   // Get Speed
   if( !( iLastLandmark->GetPositionField( EPositionFieldHorizontalSpeed,textField ) ) )
       {
       TReal32 speed;
       // Descriptor that holds the formatted speed value
       TBuf<KRealWidth> speedValue;
       // Convert the descriptor obtained into real and check if the value is 
       // indeed real.If yes then write to the encoded output. 
       TRAPD( error, PosLmConverterUtils::DesToRealL( textField, speed ) );
       
       if( !error  )
           {
           TInt speedLength = speedValue.Num( speed, realFormat );
           if( speedLength != KErrGeneral )
               {
               WriteQueryParamValueL( KUrlSpeedParam,speedValue );
               }
           }
       }
   
   // Get Heading
   if( !( iLastLandmark->GetPositionField( EPositionFieldHeading,textField ) ) )
       {
       TReal32 heading;
       
       // Descriptor that holds the formatted heading value
       TBuf<KRealWidth> headingValue;
       // Convert the descriptor obtained into real and check if the value is 
       // indeed real.If yes then write to the encoded output.
       TRAPD( error, PosLmConverterUtils::DesToRealL( textField, heading ) );
       
       if( !error )
           {
           TInt headingLength = headingValue.Num( heading, realFormat );
           if( headingLength!= KErrGeneral )
               {
               WriteQueryParamValueL( KUrlHeadingParam, headingValue );
               }
           }
       }
   
   // Get Categories that are associated with this landmark.
   // In case of local category the category name information can only be obtained  
   // if the category is added to the landmark database.In cases of global category,
   // the category name can still be obtained using the category id.
   
   // Holds the category id array 
   RArray<TPosLmItemId> categoryIdArray;
   TRAPD( error, iLastLandmark->GetCategoriesL( categoryIdArray ) );
   // Check if there are categories added
   if( !error && categoryIdArray.Count() != 0 )
       {
       // Open the default database from which the category is read by using the
       // category id
       CPosLandmarkDatabase* defaultDb = CPosLandmarkDatabase::OpenL();
       CleanupStack::PushL( defaultDb );
       ExecuteAndDeleteLD( defaultDb->InitializeL() );
       
       // Create an instance of CPosLmCategoryManager which provides method to read
       // the category from the database
       CPosLmCategoryManager* categoryManager = CPosLmCategoryManager::NewL( *defaultDb );
       CleanupStack::PushL( categoryManager );
       
       // For each of the category id,get the category name and write it to 
       // the encoded output
       for( TInt i=0;i<categoryIdArray.Count();i++ )
           {
           CPosLandmarkCategory* category = NULL;
           // Read the category info from database
           TRAPD( error, category = 
                         categoryManager->ReadCategoryLC( categoryIdArray[i] ); 
                 // If the ReadCategoryLC does not leave then pop category so as 
                 // to avoid the panic e32user::cbase71
                 if (category!=NULL) CleanupStack::Pop( category ) );
           
           // Check that there is no error while reading the category info
           if( !error )
               {
               // Push category onto the cleanupstack
               CleanupStack::PushL( category );
               // Check that the category has a name before encoding it to the output
               if( category->GetCategoryName( textField ) == KErrNone )
                   {
                   // Encode the category name before writing it to the encoded output
                   HBufC* encodedCategoryName = EncodeTextL( textField, 
                                                KUrlMaxCategoryEncodingLength );
                   CleanupStack::PushL( encodedCategoryName );
                   WriteQueryParamValueL( KUrlCategoryParam, *encodedCategoryName );
                   CleanupStack::PopAndDestroy( encodedCategoryName );
                   }
               // Pop & destroy category which was left on   cleanupstack
               CleanupStack::PopAndDestroy( category );
               }

           }
       // Pop & destroy items pushed onto the cleanup stack
       CleanupStack::PopAndDestroy( 2,defaultDb );
       }
   
   // Get Web Url field
   // Check the position fields value within the range EPositionFieldMediaLinksStart
   // and EPositionFieldMedaiLinksEnd.Consider the first field within this range that
   // has a value specified for encoding.
   TPositionFieldId id = EPositionFieldMediaLinksStart;
   while ( id <= EPositionFieldMedaiLinksEnd )
       {
       // Get position field id value
       if( iLastLandmark->GetPositionField( id, textField ) != KErrNone )
           {
           // Increment position field id 
           id++ ;
           }
       else
           {
           // Encode the Web url
           HBufC* encodedWebUrl = EncodeTextL( textField, KUrlMaxTextEncodingLength );
           CleanupStack::PushL( encodedWebUrl );
           WriteQueryParamValueL( KUrlWebParam, *encodedWebUrl );
           CleanupStack::PopAndDestroy( encodedWebUrl );
           // break the while loop after the first url is found & encoded
           break;
           }
       }
   
   // Get the timestamp
   TTime timeStamp;
   if( !( iLastLandmark->GetTimeStamp( timeStamp ) ) )
       {
       // Encode time according to the format YYYYMMDD:HHMMSS.MMMMMM
       HBufC* encodedTime = EncodeTimeL( timeStamp );
       CleanupStack::PushL( encodedTime );
       WriteQueryParamValueL( KUrlTimeStampParam, *encodedTime );
       CleanupStack::PopAndDestroy( encodedTime );
       }
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::WriteCoordinatesL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::WriteCoordinatesL( const TLocality& aPosition )
    {
    TBuf<KRealWidth> latitude;
    TBuf<KRealWidth> longitude;
    TBuf<KRealWidth> altitude;
    TBuf<KRealWidth> positionAccuracy;
    TBuf<KRealWidth> altitudeAccuracy;
    
    // Use TRealFormat for formatting the real number while converting the latitude 
    // & longitude to descriptor to display upto 6 decimal digits.
    TRealFormat realCoordinateFormat;
    realCoordinateFormat.iPoint = KRealPoint;
    realCoordinateFormat.iType = KRealFormatFixed | KDoNotUseTriads;
    realCoordinateFormat.iPlaces = KCoordinateDecimalPlaces;
    realCoordinateFormat.iWidth = KRealWidth;
    
    // Use TRealFormat for formatting the real number while converting the altitude,
    // altitudeaccuracy,position accuracy to descriptor to display upto 2 decimal
    // digits.
    TRealFormat realFormat;
    realFormat.iPoint = KRealPoint;
    realFormat.iType = KRealFormatFixed | KDoNotUseTriads;
    realFormat.iPlaces = KRealDecimalPlaces;
    realFormat.iWidth = KRealWidth;
    
    // Check that latitude & longitude values are not NAN,if yes then leave 
    // with KErrArgument as these parameters are mandatory.
    if( !Math::IsNaN( aPosition.Latitude() ) && !Math::IsNaN( aPosition.Longitude() ) )
        {
        // formatting the real number to display upto 6 decimal digits
        TInt latitudeLength = latitude.Num( aPosition.Latitude(), realCoordinateFormat );
        TInt longitudeLength = longitude.Num( aPosition.Longitude(), realCoordinateFormat );
        if( latitudeLength != KErrGeneral && longitudeLength != KErrGeneral )
            {
            // Write latitude param
            iOutput->WriteL( KUrlLatitudeParam );
            iOutput->WriteL( latitude );
                    
            // Write longitude param
            WriteQueryParamValueL( KUrlLongitudeParam,longitude );
            }
        else
            {
            User::Leave( KErrGeneral );
            }
                  
        }
    else
        {
        User::Leave( KErrArgument );
        }
    // Check that altitude value is not NaN before writing to encoded output
    if( !Math::IsNaN( aPosition.Altitude() ) )
        {
        // formatting the real number to display upto 5 decimal digits
        TInt altitudeLength = altitude.Num( aPosition.Altitude(), realFormat );
        if( altitudeLength != KErrGeneral )
            {
            // Write altitude param
            WriteQueryParamValueL( KUrlAltitudeParam,altitude );
            }
        }
    
   
    // Get Horizontal accuracy which is considered as the position accuracy here
    // Check that position accuracy is not NaN before writing to encoded output
    if( !Math::IsNaN( aPosition.HorizontalAccuracy()  ) )
        {
        // Convert horizontal accuracy to descriptor
        TInt positionAccuracyLength = positionAccuracy.Num( aPosition.HorizontalAccuracy(),
                                                            realFormat );
        if( positionAccuracyLength != KErrGeneral )
            {
            // Write the position accuracy param
            WriteQueryParamValueL( KUrlPositionAccuracyParam,positionAccuracy );            
            }
        }
    
    // Get Vertical accuracy which is considered as altitude accuracy here
    // Check that altitude accuracy is not NaN before writing to encoded output
    if( !Math::IsNaN( aPosition.VerticalAccuracy() ) )
        {
        // Convert Vertical accuracy to descriptor
        TInt altitudeAccuracyLength = altitudeAccuracy.Num( aPosition.VerticalAccuracy(),
                                                            realFormat );
        if( altitudeAccuracyLength != KErrGeneral )
            {
            // Write the altitude accuracy param
            WriteQueryParamValueL( KUrlAltitudeAccuracyParam,altitudeAccuracy );
            }
        }
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::WriteQueryParamValueL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::WriteQueryParamValueL( const TDesC16& aParam,
                                              const TDesC16& aValue )
    {
    // Write the URL query delimeter before writing the param,value pair
    iOutput->WriteL( KUrlQueryDelimeter );
    iOutput->WriteL( aParam );
    iOutput->WriteL( aValue );
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::EncodeTextL
// -----------------------------------------------------------------------------
//
HBufC* CPosLmUrlEncoder::EncodeTextL( const TDesC16& aText, const TInt aMaxEncodingLength )
    {
    TLex string( aText );
    HBufC* buffer = HBufC::NewL( aMaxEncodingLength );
    // Parse through the string and check if each of the character 
    // is either a digit/alphabet.If not get the ascii value of
    // character in hex and escape encode it.
    while( !string.Eos() )
        {
        TChar character = string.Get();
        // check if character is alpha digit
        if( !character.IsAlphaDigit() )
            {
            // Get Ascii value of character
            TInt ascii = character;
            // Check that the ascii value of the non-alphadigit 
            // character is in the range that can be encoded according 
            // to the grammar definition of URL mentioned in api spec.
            if( ( ascii >= KSpecialCharacterAsciiLowerLimit1 
                  && ascii <= KSpecialCharacterAsciiUpperLimit1 ) ||
                ( ascii >= KSpecialCharacterAsciiLowerLimit2 
                  && ascii <= KSpecialCharacterAsciiUpperLimit2 ) ||
                ( ascii >= KSpecialCharacterAsciiLowerLimit3 
                  && ascii <= KSpecialCharacterAsciiUpperLimit3 ) ||
                ( ascii >= KSpecialCharacterAsciiLowerLimit4 
                  && ascii <= KSpecialCharacterAsciiUpperLimit4 ) )
                {
                // Convert ascii in decimal to ascii in hex
                TBuf<2> buf;
                buf.Format(KUrlHex, character );
                // Write the escaped character to buffer
                buffer->Des().Append( KUrlEscapeCharacter ) ;
                buffer->Des().Append( buf ) ;
                }
            }
        else
        // Write the character as it is to the buffer if alpha/digit
            {
            buffer->Des().Append( character );
            }
        }
    // return the buffer containing the encoded text
    return buffer;
    }

// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::EncodeCategoryL
// -----------------------------------------------------------------------------
//
void CPosLmUrlEncoder::EncodeCategoryL()
    {
    TPtrC categoryName;
    // Get Categories associated with the landmark to be encoded
    for( TInt i=0;i<iCategories.Count();i++ )
       {
       // Extract the category name for each of the categories
       if( iCategories[i]->GetCategoryName( categoryName ) == KErrNone )
           {
           // Encode the category name before writing it to the encoded output
           HBufC* encodedCategoryName = EncodeTextL( categoryName, 
                                                     KUrlMaxCategoryEncodingLength );
           CleanupStack::PushL( encodedCategoryName );
           WriteQueryParamValueL( KUrlCategoryParam, *encodedCategoryName );
           CleanupStack::PopAndDestroy( encodedCategoryName );
           }
       }
    }


// -----------------------------------------------------------------------------
// CPosLmUrlEncoder::EncodeTimeL
// -----------------------------------------------------------------------------
//
HBufC* CPosLmUrlEncoder::EncodeTimeL( const TTime& aTimeStamp )
    {
    // Buffer containing the encoded time field
    HBufC* timeField = HBufC::NewL( KUrlMaxTextEncodingLength );
    // Get the date time info from TTime 
    TDateTime dateTime = aTimeStamp.DateTime();
    
    // Encode each of the date time fields into the timeField buffer
    // Format the year field according to the number of digits
    timeField->Des().AppendFormat( KYearFormat, dateTime.Year() );
        
    // Format month field according to number of digits
    timeField->Des().AppendFormat( KFormat, dateTime.Month() );
        
    
    // Format month field according to number of digits
    timeField->Des().AppendFormat( KFormat, dateTime.Day() );
         
    // Append the date time separator
    timeField->Des().Append( KDateTimeSeparator );
        
    // Format month field according to number of digits
    timeField->Des().AppendFormat( KFormat, dateTime.Hour() );
       

    // Format month field according to number of digits
    timeField->Des().AppendFormat( KFormat, dateTime.Minute() );
          
    // Format month field according to number of digits
    timeField->Des().AppendFormat( KFormat, dateTime.Second() );
           
    // Append the time microseconds separator
    timeField->Des().Append( KTimeMicroSecondSeparator );
        
    // Format the microseconds field according to number of digits
    timeField->Des().AppendFormat( KFormatMicroSeconds, dateTime.MicroSecond() );
        
    return timeField;
    
    }