filemanager/GFLM/src/CGflmFileRecognizer.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 18 Jan 2010 20:09:41 +0200
changeset 0 6a9f87576119
child 13 5181328fad28
permissions -rw-r--r--
Revision: 201001 Kit: 201003

/*
* Copyright (c) 2002-2007 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:  Recogniser wrapper
*
*/



// INCLUDE FILES
#include "CGflmFileRecognizer.h"
#include "CGflmDriveResolver.h"
#include "CGflmDriveItem.h"
#include "GflmUtils.h"
#include "GFLMConsts.h"
#include <e32svr.h>
#include <barsread.h>
#include <GflmFileExtensionMimeTypes.rsg>
#include <data_caging_path_literals.hrh> 


// CONSTANTS
_LIT( KFileExtensionResourceFile, "gflmfileextensionmimetypes.rsc" );
const TInt KMimeTypeGranularity = 10;
const TUint KPerCentToDrop = 30;
const TUint KHundredPerCent = 100;


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

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::CGflmFileRecognizer
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CGflmFileRecognizer::CGflmFileRecognizer(
        CGflmDriveResolver* aDriveResolver,
        RFs& aFs ) :
    iCache( _FOFF( CPathTypePair, iLink ) ),
    iDriveResolver( aDriveResolver ),
    iFs( aFs )
    {
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CGflmFileRecognizer::ConstructL( TInt aMemoryConsumption )
    {
    User::LeaveIfError( iApaSession.Connect() );
    iMimeTypes = new( ELeave ) CDesCArraySeg( KMimeTypeGranularity );
    iCacheMaxMemoryUsage = aMemoryConsumption;

    // Get resource drive from dll location
    TFileName dllFileName;
    Dll::FileName( dllFileName );
    TParsePtrC dllParse( dllFileName );

    TFileName resFileName;
    resFileName.Copy( dllParse.Drive() );
    resFileName.Append( KDC_RESOURCE_FILES_DIR );
    GflmUtils::EnsureFinalBackslash( resFileName );
    resFileName.Append( KFileExtensionResourceFile );

    RResourceFile resFile;
    resFile.OpenL( iFs, resFileName );
    CleanupClosePushL( resFile );
    resFile.ConfirmSignatureL();

    ConstructExtMimePairsL( resFile, R_EXT_MIME_PAIRS, iExtMimePairs );
    ConstructExtMimePairsL(
        resFile, R_REMOTE_EXT_MIME_PAIRS, iRemoteExtMimePairs );

    CleanupStack::PopAndDestroy( &resFile );
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::ConstructExtMimePairsL
//
// -----------------------------------------------------------------------------
//
void CGflmFileRecognizer::ConstructExtMimePairsL(
        RResourceFile& aResFile,
        TInt aResId,
        RPointerArray< CExtMimePair >& aPairs )
    {
    // read the pairs
    HBufC8* resData = aResFile.AllocReadLC( aResId );
    TResourceReader reader;
    reader.SetBuffer( resData );
    TInt count( reader.ReadInt16() );
    aPairs.ReserveL( count );
    for ( TInt i( 0 ); i < count; i++ )
        {
        TPtrC ext( reader.ReadTPtrC() );
        TPtrC mime( reader.ReadTPtrC() );
        CExtMimePair* pair = new (ELeave) CExtMimePair();
        CleanupStack::PushL( pair );
        pair->iExt = ext.AllocL();
        pair->iMime = mime.AllocL();
        aPairs.AppendL( pair );
        CleanupStack::Pop( pair );
        }
    CleanupStack::PopAndDestroy( resData );
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::FindMimeFromExt
//
// -----------------------------------------------------------------------------
//
TPtrC CGflmFileRecognizer::FindMimeFromExt(
        const TDesC& aExt,
        RPointerArray< CExtMimePair >& aPairs )
    {
    TInt count( aPairs.Count() );

    for( TInt i( 0 ); i < count; i++)
        {
        CExtMimePair* pair = aPairs[ i ];
        if( !aExt.CompareF( *pair->iExt ) )
            {
            return TPtrC( *pair->iMime );
            }
        }
    return TPtrC( KNullDesC );
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CGflmFileRecognizer* CGflmFileRecognizer::NewL(
        RFs& aFs,
        TInt aMemoryConsumption,
        CGflmDriveResolver* aDriveResolver )
    {
    CGflmFileRecognizer* self =
        new( ELeave ) CGflmFileRecognizer( aDriveResolver, aFs );

    CleanupStack::PushL( self );
    self->ConstructL( aMemoryConsumption );
    CleanupStack::Pop( self );

    return self;
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::~CGflmFileRecognizer
//
// -----------------------------------------------------------------------------
//
CGflmFileRecognizer::~CGflmFileRecognizer()
    {
    iApaSession.Close();

    FlushCache();

    delete iMimeTypes;

    iExtMimePairs.ResetAndDestroy();
    iExtMimePairs.Close();

    iRemoteExtMimePairs.ResetAndDestroy();
    iRemoteExtMimePairs.Close();
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::RecognizeL( const TDesC& aFilename )
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TPtrC CGflmFileRecognizer::RecognizeL( const TDesC& aFilename )
    {
    TPtrC mimeType;
    TRAPD( err, mimeType.Set( DoRecognizeL( aFilename ) ) );
    if ( err == KErrNoMemory )
        {
        FlushCache();
        return DoRecognizeL( aFilename );
        }
    User::LeaveIfError( err );
    return mimeType;
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::DoRecognizeL( const TDesC& aFilename )
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TPtrC CGflmFileRecognizer::DoRecognizeL( const TDesC& aFilename )
    {
    // Search the cache for a hit
    TInt cropPoint( aFilename.LocateReverse( KGFLMDot()[ 0 ] ) );
    TBool isRemoteDrive( EFalse );

    if ( iDriveResolver && iDriveResolver->IsRemoteDrive( aFilename ) )
        {
        isRemoteDrive = ETrue;
        }

    if( cropPoint != KErrNotFound )
        {        
        TPtrC ext( aFilename.Mid( cropPoint ) );
        TPtrC mime( FindMimeFromExt( ext, iExtMimePairs ) );
        if ( mime.Length() )
            {
            return mime;
            }

        // Use remote drive specific extension mime pairs and skip
        // content recognition because it is so slow for remote drives.
        // Mime types are resolved from extension by remote storage framework
        // anyway.
        if ( isRemoteDrive)
            {
            return FindMimeFromExt( ext, iRemoteExtMimePairs );
            }
        }
    else if ( isRemoteDrive)
        {
        // Skip content recognition for remote drives because it is so slow
        return TPtrC( KNullDesC );
        }

    TDblQueIter< CPathTypePair > pairIt( iCache );
    pairIt.SetToFirst();
    CPathTypePair* pair = NULL;
    while ( ( pair = pairIt++ ) != NULL )
        {
        TPtrC ptr( *( pair->iFilename ) );
        if( ptr.Length() == aFilename.Length() &&
           !aFilename.CompareF( ptr ) )
            {
            // Cache hit
            // Move item to the first position if not already.
            // When clearing cache, oldest items can be dropped easily.
            pair->iLink.Deque();
            iCache.AddFirst( *pair );

            if ( pair->iTypeIndex != KErrNotFound )
                {
                return iMimeTypes->MdcaPoint( pair->iTypeIndex );
                }
            return TPtrC( KNullDesC );
            }
        }

        // Cache miss
        TUid uid( KNullUid );
        TDataType datatype;

        TIMESTAMP( "GFLM AppForDocument started: " )

        // Acquire the mime-type of the file
        TInt err( iApaSession.AppForDocument( aFilename, uid, datatype ) );

        TIMESTAMP( "GFLM AppForDocument ended: " )

        if ( err != KErrNone )
            {
            // If recognition returns error, handle as unrecognized file
            ERROR_LOG1(
                "CGflmFileRecognizer::DoRecognizeL-AppForDocument=%d",
                err )
            return TPtrC( KNullDesC );
            }

        CPathTypePair* newPair = CPathTypePair::NewLC( aFilename );
        TPtrC mimeType( datatype.Des() );

        INFO_LOG2( "GFLM AppForDocument:file=%S,mime=%S", &aFilename, &mimeType )

        // Run through the mime-type list to find the correct index
        if ( mimeType.Length() )
            {
            TBool isMimeFound( EFalse );
            TInt mimeCount( iMimeTypes->MdcaCount() );
            for ( TInt j( 0 ); j < mimeCount; j++ )
                {
                if( !mimeType.CompareF( iMimeTypes->MdcaPoint( j ) ) )
                    {
                    newPair->iTypeIndex = j;
                    isMimeFound = ETrue;
                    break;
                    }
                }
            // Add mime type to list if not already added
            if ( !isMimeFound )
                {
                iMimeTypes->AppendL( mimeType );
                newPair->iTypeIndex = mimeCount;
                }
            }

        // Cleanup cache and add new pair
        CleanupStack::Pop( newPair );
        CleanupCache();
        iCacheMemoryUsage += newPair->Size();
        iCache.AddFirst( *newPair );

        if ( newPair->iTypeIndex != KErrNotFound )
            {
            return iMimeTypes->MdcaPoint( newPair->iTypeIndex );
            }
        return TPtrC( KNullDesC );
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::FlushCache( )
//
// -----------------------------------------------------------------------------
//
void CGflmFileRecognizer::FlushCache()
    {
    TDblQueIter< CPathTypePair > pairIt( iCache );
    pairIt.SetToFirst();
    CPathTypePair* pair = NULL;
    while ( ( pair = pairIt++ ) != NULL )
        {
        pair->iLink.Deque();
        delete pair;
        }
    iCacheMemoryUsage = 0;
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::CleanupCache( )
//
// -----------------------------------------------------------------------------
//
void CGflmFileRecognizer::CleanupCache( )
    {
    if( iCacheMemoryUsage > iCacheMaxMemoryUsage )
        {
        TInt dropThreshold = ( TInt ) ( ( ( ( TUint ) iCacheMaxMemoryUsage ) *
            KPerCentToDrop ) / KHundredPerCent );
        TInt droppedSize( 0 );

        TDblQueIter< CPathTypePair > pairIt( iCache );
        pairIt.SetToLast();
        CPathTypePair* pair = NULL;
        while ( ( pair = pairIt-- ) != NULL )
            {
            droppedSize += pair->Size();
            pair->iLink.Deque();
            delete pair;
            if ( droppedSize >= dropThreshold )
                {
                break;
                }
            }
        iCacheMemoryUsage -= droppedSize;
        }
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::CPathTypePair::NewLC()
// 
// -----------------------------------------------------------------------------
//
CGflmFileRecognizer::CPathTypePair*
        CGflmFileRecognizer::CPathTypePair::NewLC( const TDesC& aFilename )
    {
    CPathTypePair* self = new ( ELeave ) CPathTypePair();
    CleanupStack::PushL( self );
    self->ConstructL( aFilename );
    return self;
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::CPathTypePair::ConstructL()
// 
// -----------------------------------------------------------------------------
//
void CGflmFileRecognizer::CPathTypePair::ConstructL( const TDesC& aFilename )
    {
    iFilename = aFilename.AllocL();
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::CPathTypePair::CPathTypePair()
// 
// -----------------------------------------------------------------------------
//
CGflmFileRecognizer::CPathTypePair::CPathTypePair() :
        iTypeIndex( KErrNotFound )
    {
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::CPathTypePair::~CPathTypePair()
// 
// -----------------------------------------------------------------------------
//
CGflmFileRecognizer::CPathTypePair::~CPathTypePair()
    {
    delete iFilename;
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::CPathTypePair::Size()
// 
// -----------------------------------------------------------------------------
//
TInt CGflmFileRecognizer::CPathTypePair::Size() const
    {
    return ( sizeof( TInt ) + iFilename->Size() + sizeof( TDblQueLink ) );
    }

// -----------------------------------------------------------------------------
// CGflmFileRecognizer::CExtMimePair::~CExtMimePair()
// 
// -----------------------------------------------------------------------------
//
CGflmFileRecognizer::CExtMimePair::~CExtMimePair()
    {
    delete iExt;
    delete iMime;
    }

//  End of File