diff -r 000000000000 -r 7f85d04be362 upnpharvester/cdssync/cdssynclib/src/cdssyncimplsql.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/upnpharvester/cdssync/cdssynclib/src/cdssyncimplsql.cpp Thu Dec 17 08:52:00 2009 +0200 @@ -0,0 +1,1605 @@ +/* +* Copyright (c) 2008 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: Cds Sync Implementation +* +*/ + + + + + + +#include +#include +#include "cmsqlmainfactory.h" +#include "mcmsqlmain.h" +#include "cmsqlbaseitem.h" +#include "cmsqlgenericitem.h" +#include "cmsqlaudioitem.h" +#include "cmsqlimageitem.h" +#include "cmsqlvideoitem.h" +#include "cmsqlpropertyitem.h" +#include "cmsqlresolutionpropertyitem.h" + +#include "cdssyncimplsql.h" +#include "cdssyncsqlao.h" +#include "msdebug.h" + +// Constants +_LIT8( KXmlMimeType, "text/xml" ); +_LIT8( KSymbian, "Symbian"); +_LIT8( KSemicolon, ";"); + +_LIT8( KXmlCdsDefaultNamespace, + "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"); +_LIT8( KXmlCdsDcNamespace,"http://purl.org/dc/elements/1.1/"); +_LIT8( KXmlCdsUpnpNamespace,"urn:schemas-upnp-org:metadata-1-0/upnp/"); + +_LIT8( KAlbum, "album"); +_LIT8( KArtist, "artist"); +_LIT8( KClass, "class"); +_LIT8( KDescription,"description"); +_LIT8( KDate, "date"); +_LIT8( KGenre, "genre"); +_LIT8( KId, "id"); +_LIT8( KItem, "item"); +_LIT8( KRes, "res"); +_LIT8( KTitle, "title"); +_LIT8( KAlbumArtUri, "albumArtURI"); + +_LIT8( KBitrate, "bitrate"); +_LIT8( KDuration, "duration"); +_LIT8( KProtocolInfo, "protocolInfo"); +_LIT8( KResolution, "resolution"); +_LIT8( KSize, "size"); + +_LIT8( KAudioItem, "audioItem"); +_LIT8( KImageItem, "imageItem"); +_LIT8( KVideoItem, "videoItem"); +_LIT8( KAudioBroadCastItem, "audioItem.audioBroadcast"); +_LIT8( KVideoBroadCastItem, "videoItem.videoBroadcast"); +_LIT8( KDlnaPn, "DLNA.ORG_PN=" ); + +const TInt KAlbumIndex = 0; +const TInt KArtistIndex = 1; +const TInt KClassIndex = 2; +const TInt KGenreIndex = 3; +const TInt KResolutionIndex = 4; +const TInt KUpnpProfileIndex = 5; + +const TCmMetadataField KMetadataTypes[] = + { + ECmAlbum, ECmArtist, ECmUpnpClass, ECmGenre, ECmResolution, ECmProfileId + }; + +const TInt KMetadataTypeCount = 6; + +const TInt KParseChunkSize = 100 * KKilo; // 100 kB + +const TInt KCdsSyncMaxBufLength = 512; + +const TInt KCdsSyncPriority = CActive::EPriorityIdle; + +// -------------------------------------------------------------------------- +// CItemResource::NewLC() +// -------------------------------------------------------------------------- +CItemResource* CItemResource::NewLC() + { + CItemResource* self=new (ELeave) CItemResource(); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + + +// -------------------------------------------------------------------------- +// CItemResource::~CItemResource() +// -------------------------------------------------------------------------- +CItemResource::~CItemResource() // destruct - virtual, so no export + { + delete iDuration; + delete iBitrate; + delete iSize; + delete iResolution; + delete iProtocol; + delete iUri; + } + +// -------------------------------------------------------------------------- +// CItemResource::CItemResource() +// -------------------------------------------------------------------------- +CItemResource::CItemResource() + { + } + +// -------------------------------------------------------------------------- +// CItemResource::ConstructL() +// -------------------------------------------------------------------------- +void CItemResource::ConstructL() + { + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::NewL() +// -------------------------------------------------------------------------- +CCdsSyncImpl* CCdsSyncImpl::NewL() + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::NewL")); + CCdsSyncImpl* self = NewLC(); + CleanupStack::Pop( self ); + return self; + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::NewLC() +// -------------------------------------------------------------------------- +CCdsSyncImpl* CCdsSyncImpl::NewLC() + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::NewLC")); + + CCdsSyncImpl* self = new (ELeave) CCdsSyncImpl(); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::~CCdsSyncImpl() +// -------------------------------------------------------------------------- +CCdsSyncImpl::~CCdsSyncImpl() + { + + LOG(_L("[Cds Sync]\t CCdsSyncImpl::~CCdsSyncImpl")); + + if ( IsActive() ) + { + Cancel(); + } + + // iCurrentContent is owned and needs to be deleted here before it is set + // to NULL at CleanItemData-method. + if ( iCurrentContent ) + { + delete iCurrentContent; + } + CleanItemData(); + + iState = ECdsSyncIdle; + if ( iBackground ) + { + delete iBackground; + } + + if ( iParser ) + { + delete iParser; + } + + if ( iCurrentDocument ) + { + delete iCurrentDocument; + } + + iItemsInDb.ResetAndDestroy(); + iItemsToAdd.ResetAndDestroy(); + for ( TInt i = 0; i < iNames.Count(); i++ ) + { + iNames[ i ]->ResetAndDestroy(); + } + iNames.ResetAndDestroy(); + iFs.Close(); + + if ( iSqlAo ) + { + delete iSqlAo; + } + + if ( iMetadataDb ) + { + iMetadataDb->Close(); + } + } + + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::CCdsSyncImpl() +// -------------------------------------------------------------------------- +CCdsSyncImpl::CCdsSyncImpl() : + CActive( EPriorityStandard ), + iHashOrder( CCmSqlBaseItem::CompareByHash ), + iNameOrder( CCmSqlPropertyItem::CompareItemsByName ) + { + CActiveScheduler::Add( this ); + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ConstructL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::ConstructL() + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::ConstructL")); + + CMatchData *matchData = CMatchData::NewL(); + CleanupStack::PushL( matchData ); + matchData->SetMimeTypeL( KXmlMimeType ); + User::LeaveIfError( iFs.Connect() ); + matchData->SetVariantL( KSymbian ); + + iParser = CParser::NewL( *matchData, *this ); + CleanupStack::PopAndDestroy( matchData ); + + iBackground = CIdle::NewL( KCdsSyncPriority ); + iMetadataDb = CCmSqlMainFactory::NewCmSqlMainL( iFs ); + + } + + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ResetL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::ResetL() + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::ResetL")); + LOG(_L("[Cds Sync]\t cleaning objects..")); + iBackground->Cancel(); + if( iSqlAo && iSqlAo->IsActive() && iMetadataDb ) + { + iMetadataDb->CancelAsyncOperation(); + } + + delete iSqlAo; + iSqlAo = NULL; + + iItemsInDb.ResetAndDestroy(); + iItemsToAdd.ResetAndDestroy(); + for ( TInt i = 0; i < iNames.Count(); i++ ) + { + iNames[ i ]->ResetAndDestroy(); + } + iNames.ResetAndDestroy(); + CleanItemData(); + } + + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::InitL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::InitL( RPointerArray& aSourceDataArray, + const TInt& aDeviceId, + MCdsSyncObserver& aObserver, + TInt aAddGranularity ) + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::InitL")); + iSearchIndex = 0; + ResetL(); + + LOG(_L("[Cds Sync]\t initializing variables..")); + iObserver = &aObserver; + iSourceDataArray = &aSourceDataArray; + iSourceDataComplete = EFalse; + iState = ECdsSyncInitializing; + iUnchangedItemCount = 0; + + LOG(_L("[Cds Sync]\t creating ao..")); + iSqlAo = CCdsSyncSqlAo::NewL( + *iMetadataDb, *this, iItemsToAdd, + iItemsInDb, aAddGranularity ); + + LOG(_L("[Cds Sync]\t Requesting existing metadata..")); + iMetadataDb->SetMsId( aDeviceId ); + iMetadataDb->GetItemsL( iItemsInDb, iSqlAo->iStatus ); + + iSqlAo->iState = CCdsSyncSqlAo::ECdsSyncSqlAoInitializing; + iSqlAo->Activate(); + + LOG(_L("[Cds Sync]\t done.")); + } + + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::RunL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::RunL() + { + TRACE( Print( _L("[Cds Sync]\t CCdsSyncImpl::RunL,\ + iStatus %d iState %d"), iStatus.Int(), (TInt)iState ) ); + + switch ( iState ) + { + case ECdsSyncInitializing: + { + TInt namesCount = iNames.Count(); + TRACE( Print( + _L("[Cds Sync]\t iNames array size is %d out of %d"), + namesCount, + KMetadataTypeCount ) ); + + if ( namesCount == KMetadataTypeCount ) + { + // all arrays ready, sort them + iItemsInDb.Sort( iHashOrder ); + for ( TInt i = 0; i < KMetadataTypeCount; i++ ) + { + iNames[ i ]->Sort( iNameOrder ); + } + iState = ECdsSyncReadyToParse; + iSqlAo->iState = CCdsSyncSqlAo::ECdsSyncSqlAoIdle; + NotifySourceDataAddedL(); + } + else + { + RPointerArray* nameArray = + new (ELeave) RPointerArray(); + + iMetadataDb->GetPropertyValuesL( + *nameArray, + iSqlAo->iStatus, + KMetadataTypes[namesCount] + ); + iSqlAo->Activate(); + iNames.Append( nameArray ); + } + break; + } + default: + { + TRACE( Print( _L("[Cds Sync]\t RunL iState is \ + not ECdsSyncInitializing" ) )); + break; + } + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::DoCancel() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::DoCancel() + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::DoCancel")); + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::NotifySourceDataAddedL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::NotifySourceDataAddedL( + TBool aSourceDataComplete ) + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::NotifySourceDataAdded")); + + if ( aSourceDataComplete ) + { + iSourceDataComplete = ETrue; + } + + if ( iState == ECdsSyncReadyToParse ) + { + if ( iSourceDataArray->Count() ) + { + iCurrentDocument = ( *iSourceDataArray )[ 0 ]; + iSourceDataArray->Remove( 0 ); + iChunkIndex = 0; + iParser->ParseBeginL(); + iBackground->Start( + TCallBack( CCdsSyncImpl::BackgroundParseL, this) ); + iState = ECdsSyncParsing; + } + else if ( iSourceDataComplete ) + { + TRACE( Print( _L + ("[Cds Sync]\t parsing complete, %d items to add"), + iItemsToAdd.Count() )); + TRACE( Print( _L("[Cds Sync]\t and %d items to remove"), + iItemsInDb.Count() )); + + iState = ECdsSyncIdle; + + RemoveUnchangedItems( ); + + iSqlAo->NotifyItemsAddedL( ETrue ); + } + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ProgressL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::ProgressL( TInt aItemCount ) + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::ProgressL")); + iObserver->ProgressL( aItemCount ); + } + + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ChunkCount() +// -------------------------------------------------------------------------- +TInt CCdsSyncImpl::ChunkCount() + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::ChunkCount")); + TInt chunkCount = iSourceDataArray->Count(); + if ( iCurrentDocument ) + { + chunkCount++; + } + return chunkCount; + } + +// -------------------------------------------------------------------------- +// Increment successfully processed number +// -------------------------------------------------------------------------- +// +TInt CCdsSyncImpl::ProcessedItemCount() + { + return iProcessedItems; + } + +// -------------------------------------------------------------------------- +// Increment chuch number ( search index ) +// -------------------------------------------------------------------------- +// +void CCdsSyncImpl::SetSearchIndex( const TInt aSearchIndex ) + { + iSearchIndex = aSearchIndex; + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ChunkCompleteL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::ChunkCompleteL() + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::ChunkCompleteL")); + iObserver->ChunkCompleteL(); + iProcessedItems = 0; + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OperationsCompleteL() +// -------------------------------------------------------------------------- +#ifdef _DEBUG +void CCdsSyncImpl::OperationsCompleteL( TInt aErrCode ) +#else // _DEBUG +void CCdsSyncImpl::OperationsCompleteL( TInt /*aErrCode*/ ) +#endif // _DEBUG + { + TRACE( Print( _L + ("[Cds Sync]\t CCdsSyncImpl::OperationsCompleteL (err %d)"), + aErrCode )); + + if ( iState == ECdsSyncInitializing ) + { + RunL(); + } + else + { + iObserver->SyncCompleteL(); + iProcessedItems = 0; + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::BackgroundParseL() +// -------------------------------------------------------------------------- +TInt CCdsSyncImpl::BackgroundParseL( TAny* aCdsSync ) + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::BackgroundParseL")); + + return ((CCdsSyncImpl*)aCdsSync)->DoBackgroundParseL(); + } + + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::DoBackgroundParseL() +// -------------------------------------------------------------------------- +TInt CCdsSyncImpl::DoBackgroundParseL() + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::DoBackgroundParseL")); + if ( iCurrentDocument ) + { + + #ifdef _DEBUG + iHashTime = 0; + TTime timeBefore; + timeBefore.HomeTime(); + #endif + + TBool parseMore = + ( iCurrentDocument->Length() - iChunkIndex ) > KParseChunkSize; + TPtrC8 parseChunk = + parseMore ? + iCurrentDocument->Mid( iChunkIndex, KParseChunkSize ) : + iCurrentDocument->Mid( iChunkIndex ); + + iUnchangedItemCount = 0; + + // in case of leave that is caused by out of memory + TRAPD( error, iParser->ParseL( parseChunk ) ); + if ( error != KErrNone ) + { + TRACE( Print( _L("[Cds Sync]\t Parse error = %d"), error )); + } + + #ifdef _DEBUG + TTime timeAfter; + timeAfter.HomeTime(); + TRACE( Print( _L + ("[Cds Sync]\t parsing of %d bytes of XML took %ld microsec"), + parseChunk.Size(), + timeAfter.MicroSecondsFrom( timeBefore ).Int64() ) ); + TRACE( Print( _L + ("[Cds Sync]\t of which hash comparison took %ld microsec"), + iHashTime)); + #endif + + if ( parseMore ) + { + iChunkIndex += KParseChunkSize; + } + else + { + // in case of leave that is caused by out of memory + TRAPD( err, iParser->ParseEndL() ); + if ( err != KErrNone ) + { + TRACE( Print( _L("[Cds Sync]\t \ + ParseEndL error = %d"), err )); + } + iState = ECdsSyncReadyToParse; + delete iCurrentDocument; iCurrentDocument = NULL; + // check if there's more to parse and trap the leave + TRAPD( errOne, NotifySourceDataAddedL() ); + if ( errOne != KErrNone ) + { + TRACE( Print( _L("[Cds Sync]\t NotifySourceDataAdded \ + error = %d"), errOne )); + } + ChunkCompleteL(); + } + iSqlAo->NotifyItemsAddedL(); + + return parseMore; + + } + LOG(_L("[Cds Sync]\t CCdsSyncImpl::BackgroundParseL END")); + return EFalse; + } + + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::FindAttribute() +// -------------------------------------------------------------------------- +TInt CCdsSyncImpl::FindAttribute( const TDesC8& aName, + const TDesC8& aPref, + const RAttributeArray& aAttributes ) const + { + TInt returnvalue = KErrNotFound; + for ( TInt i = 0; i < aAttributes.Count(); i++ ) + { + if ( ( aAttributes[i].Attribute().LocalName(). + DesC().Compare( aName ) == 0) && + ( aAttributes[i].Attribute().Prefix(). + DesC().Compare( aPref ) == 0) ) + { + returnvalue = i; + // break out from the loop + i = aAttributes.Count(); + } + } + return returnvalue; + } + + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ParseResolution() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::ParseResolution( const TDesC8& aDes, + TUint& aWidth, + TUint& aHeight ) const + { + TLex8 lex( aDes ); + if ( lex.Val( aWidth ) != KErrNone ) + { + aWidth = 0; + } + if ( lex.Get() != 'x' || lex.Val( aHeight ) != KErrNone ) + { + aHeight = 0; + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ParseUint() +// -------------------------------------------------------------------------- +TUint CCdsSyncImpl::ParseUint( const TDesC8& aDes ) const + { + TUint res = 0; + TLex8 lex( aDes ); + if ( lex.Val( res ) != KErrNone ) + { + res = 0; + } + return res; + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ParseInt64() +// -------------------------------------------------------------------------- +TInt64 CCdsSyncImpl::ParseInt64( const TDesC8& aDes ) const + { + TInt64 res = 0; + TLex8 lex( aDes ); + if ( lex.Val( res ) != KErrNone ) + { + res = 0; + } + return res; + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ParseTime() +// -------------------------------------------------------------------------- +TTime CCdsSyncImpl::ParseTime( const TDesC8& aDes ) const + { + TUint year = 0; + TUint month = 1; + TUint day = 1; + TLex8 lex; + + TInt dashpos = aDes.Find( _L8("-") ); + TInt dashpos2 = aDes.Mid( dashpos + 1 ).Find( _L8("-") ) + dashpos + 1; + + lex = aDes.Left(4); + if ( lex.Val( year ) != KErrNone ) + { + year = 0; + } + if ( dashpos2-dashpos > 1 ) + { + lex = aDes.Mid( dashpos + 1,dashpos2 - dashpos - 1 ); + if ( lex.Val(month) != KErrNone ) + { + month = 1; + } + + } + if (aDes.Length() - dashpos2 > 1) + { + lex = aDes.Mid(dashpos2 + 1); + if ( lex.Val(day) != KErrNone ) + { + day = 1; + } + } + TDateTime time; + if ( time.Set(year, TMonth(month-1), day-1, 0,0,0,0) != KErrNone ) + { + return TTime( TDateTime(0, TMonth(0), 0, 0,0,0,0) ); + } + else + { + return TTime( time ); + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ParseDuration() +// -------------------------------------------------------------------------- +TReal CCdsSyncImpl::ParseDuration( const TDesC8& aDes ) const + { + TInt multiplier = 1; + TInt plusminuspos = aDes.Find( _L8("-") ); + if ( plusminuspos == KErrNotFound ) + { + plusminuspos = aDes.Find( _L8("+") ); + } + else + { + multiplier = -1; + } + + TInt hourminutepos = aDes.Find( _L8(":") ); + TInt minutesecondpos = aDes.Mid( hourminutepos + 1 ). + Find( _L8(":") ) + hourminutepos + 1; + TInt dotpos = aDes.Find( _L8(".") ); + TInt slashpos = aDes.Find( _L8("/") ); + + TInt hours = 0; TInt minutes = 0; + TReal seconds = 0; TReal f0 = 0; TReal f1=1; + TLex8 lex; + + if ( hourminutepos - plusminuspos > 1 ) + { + lex = aDes.Mid( plusminuspos + 1, hourminutepos - plusminuspos - 1 ); + if ( lex.Val( hours ) != KErrNone ) + { + hours = 0; + } + } + if ( minutesecondpos - hourminutepos > 1 ) + { + lex = aDes.Mid( hourminutepos + 1, + minutesecondpos - hourminutepos - 1 ); + if ( lex.Val(minutes) != KErrNone ) + { + minutes = 0; + } + } + if ( (dotpos == KErrNotFound || slashpos == KErrNotFound) + && minutesecondpos != KErrNotFound ) + { + lex = aDes.Mid( minutesecondpos + 1 ); + if ( lex.Val(seconds) != KErrNone ) + { + seconds = 0; + } + } + else if (slashpos - dotpos > 1 && dotpos - minutesecondpos > 1 + && aDes.Length() - slashpos > 1) + { + lex = aDes.Mid( minutesecondpos + 1, dotpos - minutesecondpos - 1 ); + if ( lex.Val( seconds ) != KErrNone ) + { + seconds = 0; + } + lex = aDes.Mid( dotpos + 1, slashpos - dotpos - 1 ); + if ( lex.Val(f0) != KErrNone ) + { + f0 = 0; + } + lex = aDes.Mid( slashpos + 1 ); + if ( lex.Val(f1) != KErrNone ) + { + f1 = 1; + } + } + + return multiplier*(hours * 3600 + minutes * 60 + seconds + f0/f1); + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::CalculateHashL() +// -------------------------------------------------------------------------- +HBufC8* CCdsSyncImpl::CalculateHashL() const + { + CSHA1* sha1 = CSHA1::NewL(); + CleanupStack::PushL( sha1 ); + sha1->Reset(); + + if ( iArtist ) + { + sha1->Update( *iArtist ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + if ( iAlbum ) + { + sha1->Update( *iAlbum ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + if ( iTitle ) + { + sha1->Update( *iTitle ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + if ( iClass ) + { + sha1->Update( *iClass ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + if ( iGenre ) + { + sha1->Update( *iGenre ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + if ( iDate ) + { + sha1->Update( *iDate ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + if( iAlbumArtUri ) + { + sha1->Update( *iAlbumArtUri ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + for ( TInt i = 0; i < iResources.Count(); i++ ) + { + CItemResource* res = iResources[i]; + + if ( res->iBitrate ) + { + sha1->Update( *res->iBitrate ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + if ( res->iSize ) + { + sha1->Update( *res->iSize ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + + if ( res->iResolution ) + { + sha1->Update( *res->iResolution ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + + if ( res->iDuration ) + { + sha1->Update( *res->iDuration ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + if ( res->iProtocol ) + { + sha1->Update( *res->iProtocol ); + } + else + { + sha1->Update( KNullDesC8() ); + } + + if ( res->iUri ) + { + sha1->Update( *res->iUri ); + } + else + { + sha1->Update( KNullDesC8() ); + } + } + + // get the final hash value. + TPtrC8 hash = sha1->Final(); + + // create an object that can be returned and copy hash value there. + HBufC8* retval = hash.AllocL(); + + // delete SHA1 object. + CleanupStack::PopAndDestroy( sha1 ); + sha1 = NULL; + + // return + return retval; + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::EscapeHashLC() +// -------------------------------------------------------------------------- +HBufC* CCdsSyncImpl::EscapeHashLC( const TDesC8& aHash ) const + { + HBufC* escapedHash = HBufC::NewLC( 40 ); + TPtr ptr = escapedHash->Des(); + for ( TInt i=0; i < 20; i++ ) + { + if ( aHash[i] == 0 ) + { + ptr.Append( _L("\\0") ); + } + else if ( aHash[i] == '\\' ) + { + ptr.Append( _L("\\\\") ); + } + else + { + ptr.Append( aHash[i] ); + } + } + return escapedHash; + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::GetPropertyIdL() +// -------------------------------------------------------------------------- +TInt64 CCdsSyncImpl::GetPropertyIdL( TInt aMetadataIndex, + const TDesC8& aValue ) const + { + TInt64 id = 0; + + TCmMetadataField metadataType = KMetadataTypes[ aMetadataIndex ]; + + CCmSqlPropertyItem* property = NULL; + if ( metadataType == ECmResolution ) + { + property = CCmSqlResolutionPropertyItem::NewLC(); + } + else + { + property = CCmSqlPropertyItem::NewLC(); + } + + + property->SetNameL( aValue ); + CCmSqlPropertyItemArray* properties = iNames[ aMetadataIndex ]; + TInt index = properties->FindInOrder( property, iNameOrder ); + + + if ( index == KErrNotFound ) + { + if ( metadataType == ECmResolution ) + { + TUint width = 0; + TUint height = 0; + ParseResolution( aValue, width, height ); + + CCmSqlResolutionPropertyItem* resolutionProperty = + static_cast ( property ); + resolutionProperty->SetWidth( width ); + resolutionProperty->SetHeight( height ); + resolutionProperty->SetPixelCount( width * height ); + } + + property->SetStatus( EFalse ); + + iMetadataDb->SyncAddPropertyItemL( + *property, metadataType ); + properties->InsertInOrder( property, iNameOrder ); + id = property->Id(); + CleanupStack::Pop( property ); + } + else + { + id = (*properties)[ index ]->Id(); + CleanupStack::PopAndDestroy( property ); + } + + return id; + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::CleanItemData() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::CleanItemData() + { + iCurrentContent = NULL; + + delete iItemId; + iItemId = NULL; + + delete iArtist; + iArtist = NULL; + + delete iAlbum; + iAlbum = NULL; + + delete iTitle; + iTitle = NULL; + + delete iClass; + iClass = NULL; + + delete iGenre; + iGenre = NULL; + + delete iDate; + iDate = NULL; + + delete iDescription; + iDescription = NULL; + + delete iAlbumArtUri; + iAlbumArtUri = NULL; + + iResources.ResetAndDestroy(); + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OnStartDocumentL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnStartDocumentL( const RDocumentParameters&/*aDocParam*/, + TInt aErrorCode ) + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::OnStartDocumentL")); + + if ( aErrorCode ) + { + iObserver->SyncErrorL( aErrorCode ); + } + + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OnEndDocumentL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnEndDocumentL( TInt aErrorCode ) + { + LOG(_L("[Cds Sync]\t CCdsSyncImpl::OnEndDocumentL")); + + if (aErrorCode) + { + iObserver->SyncErrorL( aErrorCode ); + } + + + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OnStartElementL( +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnStartElementL( const RTagInfo& aElement, + const RAttributeArray& aAttributes, + TInt aErrorCode ) + { + + if ( aErrorCode ) + { + iObserver->SyncErrorL( aErrorCode ); + } + + delete iCurrentContent; + iCurrentContent = NULL; + + const TDesC8& name = aElement.LocalName().DesC(); + const TDesC8& uri = aElement.Uri().DesC(); + + if ( !uri.Compare( KXmlCdsDefaultNamespace ) ) + { + if ( !name.Compare( KItem ) ) // + { + TInt id = FindAttribute( KId, _L8(""), aAttributes ); + if ( id != KErrNotFound) + { + CleanItemData(); + iItemId = aAttributes[ id ].Value().DesC().AllocL(); + } + } + else if ( !name.Compare( KRes ) ) // + { + + CItemResource* res = CItemResource::NewLC(); + + for (TInt i = 0; i < aAttributes.Count(); i++) + { + + const TDesC8& attrName = + aAttributes[i].Attribute().LocalName().DesC(); + HBufC8* attrValue = aAttributes[i].Value().DesC().AllocL(); + + if ( !attrName.Compare( KBitrate ) ) + { + res->iBitrate = attrValue; + } + else if ( !attrName.Compare( KSize ) ) + { + res->iSize = attrValue; + } + else if ( !attrName.Compare( KDuration ) ) + { + res->iDuration = attrValue; + } + else if ( !attrName.Compare( KResolution ) ) + { + res->iResolution = attrValue; + } + else if ( !attrName.Compare( KProtocolInfo ) ) + { + res->iProtocol = attrValue; + } + } + iResources.Append( res ); + CleanupStack::Pop( res ); + } + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OnEndElementL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnEndElementL( const RTagInfo& aElement, + TInt aErrorCode ) + { + if ( aErrorCode ) + { + iObserver->SyncErrorL( aErrorCode ); + } + + const TDesC8& name = aElement.LocalName().DesC(); + const TDesC8& uri = aElement.Uri().DesC(); + + if ( !uri.Compare( KXmlCdsDefaultNamespace ) ) + // element from DIDL-Lite namespace + { + if ( !name.Compare( KRes ) && iCurrentContent ) // + { + // remove "http://" and IP from URI + TInt httpPos = iCurrentContent->Find( _L8("http://") ); + if ( httpPos != KErrNotFound ) + { + TInt ipLength = + iCurrentContent->Mid( httpPos + 7 ).Find(_L8("/")); + if ( ipLength != KErrNotFound ) + { + iCurrentContent->Des().Delete(0, httpPos + 7 + ipLength); + } + } + iResources[ iResources.Count() - 1 ]->iUri = iCurrentContent; + } + + else if ( !name.Compare( KItem )) // + { + // calc hash and construct item here + HBufC8* hash = CalculateHashL(); + CleanupStack::PushL( hash ); + HBufC* escapedHash = EscapeHashLC( *hash ); + CleanupStack::Pop( escapedHash ); + + CleanupStack::PopAndDestroy( hash ); + hash = NULL; + CleanupStack::PushL( escapedHash ); + + CCmSqlBaseItem* baseItem = CCmSqlBaseItem::NewLC(); + baseItem->SetHashL( *escapedHash ); + TInt index = iItemsInDb.FindInOrder( baseItem, iHashOrder ); + CleanupStack::PopAndDestroy( baseItem ); + + if ( index == KErrNotFound ) // new or modified item + { + CCmSqlGenericItem* item = NULL; + + // find relevant resources + CItemResource* httpRes = NULL; + CItemResource* internalRes = NULL; + for ( TInt i=0; i < iResources.Count(); i++ ) + { + HBufC8* protocol = iResources[ i ]->iProtocol; + if ( protocol ) + { + if ( !httpRes && + protocol->Find(_L8("http-get:")) + != KErrNotFound ) + { + httpRes = iResources[ i ]; + } + else if ( !internalRes && + protocol->Find(_L8("internal:")) + != KErrNotFound ) + { + internalRes = iResources[ i ]; + } + } + } + + if( iClass && iClass->Find( KAudioBroadCastItem ) != + KErrNotFound ) + { + // create audio item and set audio specific properties + CCmSqlAudioItem* audioItem = CCmSqlAudioItem::NewLC(); + audioItem->SetMediaType( ECmAudioBroadCast ); + if ( iGenre ) + { + audioItem->SetGenreId( + GetPropertyIdL( KGenreIndex, *iGenre ) ); + } + item = audioItem; + CleanupStack::Pop( audioItem ); + } + + else if( iClass && iClass->Find( KVideoBroadCastItem ) != + KErrNotFound ) + { + // create video item and set image specific properties + CCmSqlVideoItem* videoItem = CCmSqlVideoItem::NewLC(); + videoItem->SetMediaType( ECmVideoBroadCast ); + if ( iGenre ) + { + videoItem->SetGenreId( + GetPropertyIdL( KGenreIndex, *iGenre ) ); + } + item = videoItem; + CleanupStack::Pop( videoItem ); + } + + else if ( iClass && + iClass->Find( KAudioItem ) != KErrNotFound ) + { + // create audio item and set audio specific properties + CCmSqlAudioItem* audioItem = CCmSqlAudioItem::NewLC(); + audioItem->SetMediaType( ECmAudio ); + if ( iAlbum ) + { + audioItem->SetAlbumId( + GetPropertyIdL( KAlbumIndex, *iAlbum ) ); + } + if ( iArtist ) + { + audioItem->SetArtistId( + GetPropertyIdL( KArtistIndex, *iArtist ) ); + } + if ( iGenre ) + { + audioItem->SetGenreId( + GetPropertyIdL( KGenreIndex, *iGenre ) ); + } + if( iAlbumArtUri ) + { + audioItem->SetAlbumArtUriL( *iAlbumArtUri ); + } + if ( httpRes && httpRes->iDuration ) + { + audioItem->SetDuration( + (TInt) ParseDuration( *httpRes->iDuration ) ); + } + if ( httpRes && httpRes->iBitrate ) + { + audioItem->SetBitrate( + ParseUint( *httpRes->iBitrate ) ); + } + item = audioItem; + CleanupStack::Pop( audioItem ); + } + + else if ( iClass && + iClass->Find( KImageItem ) != KErrNotFound ) + { + // create image item and set image specific properties + CCmSqlImageItem* imageItem = CCmSqlImageItem::NewLC(); + imageItem->SetMediaType( ECmImage ); + + if ( iDescription ) + { + imageItem->SetDescriptionL( *iDescription ); + } + if ( internalRes && internalRes->iResolution ) + { + imageItem->SetResolutionId( + GetPropertyIdL( KResolutionIndex, + *internalRes->iResolution )); + } + item = imageItem; + CleanupStack::Pop( imageItem ); + } + else if ( iClass && + iClass->Find( KVideoItem ) != KErrNotFound ) + { + // create video item and set image specific properties + CCmSqlVideoItem* videoItem = CCmSqlVideoItem::NewLC(); + videoItem->SetMediaType( ECmVideo ); + if ( iGenre ) + { + videoItem->SetGenreId( + GetPropertyIdL( KGenreIndex, *iGenre ) ); + } + item = videoItem; + CleanupStack::Pop( videoItem ); + } + + if ( item ) + { + CleanupStack::PushL( item ); + // Parsing dlna profile id from protocol info + ParseProfileIdL( *item, *httpRes ); + ParseProfileIdL( *item, *internalRes ); + // set general properties + item->SetHashL( *escapedHash ); + item->SetCdsIdL( *iItemId ); + if ( iClass ) + { + item->SetUpnpclassId( + GetPropertyIdL( KClassIndex, *iClass ) ); + } + if ( iTitle ) + { + item->SetTitleL( *iTitle ); + } + if ( iDate ) + { + item->SetDate( ParseTime( *iDate ) ); + } + if ( httpRes && httpRes->iUri ) + { + item->SetUriL( *httpRes->iUri ); + } + if ( httpRes && httpRes->iSize ) + { + item->SetSize( ParseUint( *httpRes->iSize ) ); + } + else if ( internalRes && internalRes->iSize ) + { + item->SetSize( ParseUint( *internalRes->iSize ) ); + } + TTime currentTime; + currentTime.HomeTime(); + item->SetHarvestDate( currentTime ); + item->SetSearchId( iSearchIndex ); + iItemsToAdd.Append( item ); // transfer ownership + ProgressL(1); + iProcessedItems++; + CleanupStack::Pop( item ); + } + else + { + LOG(_L("[Cds Sync]\t item == NULL ")); + } + } + else // unchanged item + { + CCmSqlBaseItem* itemToRemove = iItemsInDb[ index ]; + iItemsInDb.Remove( index ); + ProgressL(1); + iProcessedItems++; + delete itemToRemove; + } + CleanItemData(); + CleanupStack::PopAndDestroy( escapedHash ); + } + } + + else if ( !uri.Compare( KXmlCdsDcNamespace ) ) + // element from dc namespace + { + if ( !name.Compare( KTitle ) ) // + { + iTitle = iCurrentContent; + } + else if ( !name.Compare( KDate ) ) // + { + iDate = iCurrentContent; + } + else if ( !name.Compare( KDescription ) ) // + { + iDescription = iCurrentContent; + } + } + + else if ( !uri.Compare( KXmlCdsUpnpNamespace ) ) + // element from UPnP namespace + { + if ( !name.Compare( KAlbum ) ) // + { + iAlbum = iCurrentContent; + } + else if ( !name.Compare( KArtist ) ) // + { + iArtist = iCurrentContent; + } + else if ( !name.Compare( KClass ) ) // + { + iClass = iCurrentContent; + } + else if ( !name.Compare( KGenre ) ) // + { + iGenre = iCurrentContent; + } + else if ( !name.Compare( KAlbumArtUri ) ) // + { + // Parse uri removes ip and port for iCurrentContent + ParseUri(); + iAlbumArtUri = iCurrentContent; + } + } + else + { + delete iCurrentContent; + } + + iCurrentContent = NULL; + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OnContentL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnContentL( const TDesC8& aBytes, TInt aErrorCode ) + { + if ( aErrorCode ) + { + iObserver->SyncErrorL( aErrorCode ); + } + if ( iCurrentContent ) + { + if( iCurrentContent->Length() + aBytes.Length() < + KCdsSyncMaxBufLength ) + { + iCurrentContent->Des().Append( aBytes ); + } + else + { + iCurrentContent = iCurrentContent->ReAllocL( + iCurrentContent->Length() + aBytes.Length() ); + iCurrentContent->Des().Append( aBytes ); + } + } + else + { + iCurrentContent = HBufC8::NewL( KCdsSyncMaxBufLength ); + iCurrentContent->Des().Append( aBytes ); + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OnStartPrefixMappingL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnStartPrefixMappingL( const RString& /* aPrefix */, + const RString& /* aUri */, + TInt aErrorCode ) + { + if (aErrorCode) + { + iObserver->SyncErrorL( aErrorCode ); + } + + + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OnEndPrefixMappingL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnEndPrefixMappingL( const RString& /* aPrefix */, + TInt aErrorCode ) + { + if (aErrorCode) + { + iObserver->SyncErrorL( aErrorCode ); + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OnIgnorableWhiteSpaceL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnIgnorableWhiteSpaceL( const TDesC8& /* aBytes */, + TInt aErrorCode ) + { + if (aErrorCode) + { + iObserver->SyncErrorL( aErrorCode ); + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OnSkippedEntityL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnSkippedEntityL( const RString& /* aName */, + TInt aErrorCode ) + { + if (aErrorCode) + { + iObserver->SyncErrorL( aErrorCode ); + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::OnProcessingInstructionL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnProcessingInstructionL( const TDesC8& /* aTarget */, + const TDesC8& /* aData */, + TInt aErrorCode ) + { + if (aErrorCode) + { + iObserver->SyncErrorL( aErrorCode ); + } + } + +// -------------------------------------------------------------------------- +// void CCdsSyncImpl::OnError() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::OnError( TInt aErrorCode ) + { + if (aErrorCode && iState != ECdsSyncIdle) + { + TRAP_IGNORE( iObserver->SyncErrorL( aErrorCode ) ); + } + + + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::GetExtendedInterface() +// -------------------------------------------------------------------------- +TAny* CCdsSyncImpl::GetExtendedInterface( const TInt32 /* aUid */ ) + { + return NULL; + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ParseProfileIdL() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::ParseProfileIdL( + CCmSqlGenericItem& aItem, + const CItemResource& aRes ) const + { + if( &aRes && &aItem ) + { + TInt index( aRes.iProtocol->Find( KDlnaPn() ) ); + if( KErrNotFound != index ) + { + TInt index2( aRes.iProtocol->Find( KSemicolon() ) ); + if( KErrNotFound != index2 ) + { + HBufC8* temp = + aRes.iProtocol->Mid( + index + KDlnaPn().Length(), + index2 - ( index + KDlnaPn().Length() ) ).AllocLC(); + aItem.SetUpnpProfileId( + GetPropertyIdL( KUpnpProfileIndex, *temp ) ); + CleanupStack::PopAndDestroy( temp ); + } + } + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::RemoveUnchangedItems() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::RemoveUnchangedItems() + { + for( TInt i = iItemsInDb.Count() - 1; i >= 0; i-- ) + { + if( iItemsInDb[i]->SearchId() < iSearchIndex ) + { + CCmSqlBaseItem* itemToRemove = iItemsInDb[ i ]; + iItemsInDb.Remove( i ); + delete itemToRemove; + } + } + } + +// -------------------------------------------------------------------------- +// CCdsSyncImpl::ParseUri() +// -------------------------------------------------------------------------- +void CCdsSyncImpl::ParseUri() + { + // Removes ip and port from iCurrentContent + TInt httpPos = iCurrentContent->Find( _L8("http://") ); + if ( httpPos != KErrNotFound ) + { + TInt ipLength = + iCurrentContent->Mid( httpPos + 7 ).Find(_L8("/")); + if ( ipLength != KErrNotFound ) + { + iCurrentContent->Des().Delete(0, httpPos + 7 + ipLength); + } + } + } + +// End of file