mmserv/metadatautility/Src/MetaDataBufferAgg.cpp
changeset 0 71ca22bcf22a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmserv/metadatautility/Src/MetaDataBufferAgg.cpp	Tue Feb 02 01:08:46 2010 +0200
@@ -0,0 +1,485 @@
+/*
+* 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:  Active object for buffer aggregation
+*
+*/
+
+
+// INCLUDE FILES
+#include "MetaDataUtilityBody.h"
+#include "MDUChunkDataObserver.h"
+#include "MetaDataBufferAgg.h"
+
+// CONSTANTS
+// (ID3v2 specification found in www.id3.org)
+// ID3v2 header consists of following parts:
+// - identifier "ID3", 3 bytes
+// - version, 2 bytes
+// - flags, 1 byte
+// - data length, 4 bytes
+const TInt KID3v2HeaderLength           = 10;
+const TInt KID3v2TagLength              = 3;
+
+_LIT8( KID3v2Tag, "ID3" );              // ID3 metadata format indication
+
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::MetaDataBufferAgg
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMetaDataBufferAgg::CMetaDataBufferAgg( CMetaDataUtilityBody* aBody,
+        MMDUChunkDataObserver& aObserver )  
+: CActive( CActive::EPriorityStandard ), 
+  iBody( aBody ),
+  iObserver( aObserver ),
+  iState( EFindIdentifier ),
+  iUserChunk( NULL ),
+  iFinalChunk( EFalse ),
+  iMetaDataSize( 0 )  
+    {
+    CActiveScheduler::Add( this );
+    }
+
+// ---------------------------------------------------------------------------
+// Two-Phase Constructor
+// ---------------------------------------------------------------------------
+//
+CMetaDataBufferAgg* CMetaDataBufferAgg::NewL( CMetaDataUtilityBody* aBody,
+        TDesC8& aMimeType, 
+        MMDUChunkDataObserver& aObserver  )
+    {
+    CMetaDataBufferAgg* self = new(ELeave) CMetaDataBufferAgg( aBody, aObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL( aMimeType );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::Construct()
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::ConstructL( const TDesC8& aMimeType )
+    {
+    // copy MimeType
+    iMimeType.CreateL( aMimeType.Size() );    
+    iMimeType = aMimeType;
+    
+    // allocate the buffers
+    iPrevBuf.CreateL( 0 );
+    iMetaDataBuf.CreateL ( 0 );
+    
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::~CMetaDataBufferAgg()
+// -----------------------------------------------------------------------------
+//
+CMetaDataBufferAgg::~CMetaDataBufferAgg()
+    {
+    iMimeType.Close();
+    iPrevBuf.Close();
+    iMetaDataBuf.Close();
+    Cancel();
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::RequestProcessChunkData
+// -----------------------------------------------------------------------------
+//
+TInt CMetaDataBufferAgg::RequestProcessChunkData( TDesC8& aChunk, 
+        TBool aFinalChunk )
+    {
+    if (iState == EParseComplete )
+        {
+        return KErrAlreadyExists;
+        }
+    if (iState == EParseData )
+        {
+        return KErrCompletion;
+        }
+    if ( IsActive() )
+        {
+        return KErrNotReady;
+        }
+    
+    iUserChunk = &aChunk;
+    iFinalChunk = aFinalChunk;
+
+    iStatus = KRequestPending;
+    SetActive();  
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::RequestParseChunkData
+// -----------------------------------------------------------------------------
+//
+TInt CMetaDataBufferAgg::RequestParseChunkData()
+    {
+    if (iState == EParseComplete )
+        {
+        return KErrAlreadyExists;
+        }
+    if ( IsActive() || iState != EParseData)
+        {
+        return KErrNotReady;
+        }
+
+    
+    iStatus = KRequestPending;
+    SetActive();  
+
+    return KErrNone;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::ReadyToGo
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::ReadyToGo()
+{
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete( status, KErrNone );
+}
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::DoCancel
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::DoCancel()
+    {
+    }
+    
+// -----------------------------------------------------------------------------
+// CMetaDataUtility::RunL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::RunL()
+    {
+
+    switch( iState )
+        {
+        case EFindIdentifier:
+              {
+              TRAPD( err, FindMetaDataIdentifierL( iUserChunk ));
+              DoCallback( err );
+              break;
+              }
+        case ECalculateSize:
+              {
+              TRAPD( err, CalculateMetaDataSizeL( iUserChunk ));
+              DoCallback( err );
+              break;
+              }
+        case ECollectData:
+             {
+             TRAPD( err, CollectMetaDataL( iUserChunk ));  
+             DoCallback( err );
+             break;
+             }
+        case EParseData:
+             {
+             TRAPD( err, iBody->DoParseChunkDataL( iMetaDataBuf, iMimeType )); 
+             iState = EParseComplete;
+             DoCallback( err );
+             break;
+             }
+        default:
+             break;
+        }
+      }
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::DoCallback
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::DoCallback( TInt aError)
+    {
+    if ( iFinalChunk )
+        { 
+        switch (iState)
+            {            
+            case EFindIdentifier:
+            case ECalculateSize:
+                {
+                iObserver.HandleChunkDataProcessed( KErrNotFound );                                              
+                break;
+                }
+            case ECollectData:
+            case EParseData:
+                { 
+                iState = EParseData;
+                iObserver.HandleChunkDataReadyToBeParsed();
+                break;
+                }
+            case EParseComplete:
+                {
+                iObserver.HandleChunkDataComplete( aError );                                              
+                break;
+                }
+            }
+        }
+    else
+        {
+        switch (iState)
+            {            
+            case EFindIdentifier:
+            case ECalculateSize:
+            case ECollectData:
+                {
+                iObserver.HandleChunkDataProcessed( KErrNone );                                               
+                break;
+                }
+            case EParseData:
+                { 
+                iObserver.HandleChunkDataReadyToBeParsed();
+                break;
+                }
+            case EParseComplete:
+                {
+                iObserver.HandleChunkDataComplete( aError );                                              
+                break;
+                }
+            }        
+        }
+        
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::FindMetaDataIdentifier
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::FindMetaDataIdentifierL( TDesC8* aBuf )
+    {
+    // search from client buffer first
+    TInt offset = aBuf->Find( KID3v2Tag );
+    if ( offset != KErrNotFound )
+        {
+        // Identifier is found, copy to iMetaDataBuf
+        TUint8* ptr = const_cast<TUint8*>(aBuf->Ptr());
+        CopyBufferL( &iMetaDataBuf, ptr+offset, aBuf->Size() - offset );
+                      
+        ComputeSize( &iMetaDataBuf, 0 );
+
+        if ( !iMetaDataSize )
+            {
+            iState = ECalculateSize;              
+            }
+        else
+            {
+            if ( iMetaDataBuf.Size() >= iMetaDataSize )
+                {
+                iState = EParseData;      
+                }  
+            else
+                {
+                iState = ECollectData;                              
+                }
+            }       
+        }
+    else
+        {
+        // Identifier is NOT found, need to process the previous data
+         ProcessPreviousChunkL( aBuf );
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::FindMetaDataIdentifier
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::ProcessPreviousChunkL( TDesC8* aBuf )
+    {
+    TInt prevSize = iPrevBuf.Size();   
+    TInt bufSize = aBuf->Size();
+    TInt sizeToCopy = 0;
+    
+    //If there is not enough data for 2*KID3v2TagLength
+    //The following lists the posibility of the iPrevBuf content:
+    //      . . . . . .
+    //      . . . . . I
+    //      . . . . I D
+    //      . . I D 3 .
+    //  or it contains "ID3" at different byte
+    if ( prevSize + bufSize < 2*KID3v2TagLength )
+        {
+        TUint8* ptr = const_cast<TUint8*> (aBuf->Ptr());
+        
+        // just do the append
+        AppendBufferL( &iPrevBuf, ptr, bufSize );
+        return;
+        }
+    else
+        {
+        sizeToCopy = 2*KID3v2TagLength - prevSize;
+        }
+       
+    //Add into the previous buf (iPrevBuf)
+    TUint8* ptr = const_cast<TUint8*> (aBuf->Ptr());
+    AppendBufferL( &iPrevBuf, ptr, sizeToCopy );    
+    
+    // search from previous buffer 
+    TInt offset = iPrevBuf.Find( KID3v2Tag );
+    
+    // tag IS found
+    if ( offset != KErrNotFound )
+        {
+        //Found identifier, save previous buf data into iMetaDataBuf
+        ptr = const_cast<TUint8*> (iPrevBuf.Ptr());
+        AppendBufferL( &iMetaDataBuf, ptr+offset, iPrevBuf.Size() - offset );
+        
+        //Append the rest of aBuf
+        ptr = const_cast<TUint8*> (aBuf->Ptr());
+        AppendBufferL( &iMetaDataBuf, ptr+sizeToCopy, aBuf->Size() - sizeToCopy );
+                
+        ComputeSize( &iMetaDataBuf, 0 );  
+        if ( !iMetaDataSize )
+            {
+            iState = ECalculateSize;              
+            }
+        else
+            {
+            if ( iMetaDataBuf.Size() >= iMetaDataSize )
+                {
+                iState = EParseData;      
+                }  
+            else
+                {
+                iState = ECollectData;                              
+                }
+            }     
+        }
+    
+    // tag NOT found
+    else
+        {
+        //Re-populate iPrevBuf 
+        if ( aBuf->Size() < KID3v2TagLength )
+            {
+            //Append the rest of aBuf into iPrevBuf
+            ptr = const_cast<TUint8*> (aBuf->Ptr());        
+            AppendBufferL( &iPrevBuf, ptr+sizeToCopy, aBuf->Size() - sizeToCopy );
+            
+            //copy the last "KID3v2TagLength" size of aBuf into iPrevBuf
+            iPrevBuf = iPrevBuf.Mid(iPrevBuf.Size() - KID3v2TagLength);
+            }
+        else
+            {
+            //copy the last "KID3v2TagLength" size of aBuf into iPrevBuf
+            offset = aBuf->Size() - KID3v2TagLength;
+            TUint8* ptr = const_cast<TUint8*>(aBuf->Ptr());
+            CopyBufferL( &iPrevBuf, ptr+offset, KID3v2TagLength );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::CalculateMetaDataSize
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::CalculateMetaDataSizeL( TDesC8* aBuf )
+    {
+    TUint8* ptr = const_cast<TUint8*> (aBuf->Ptr());
+    AppendBufferL( &iMetaDataBuf, ptr, aBuf->Size() );    
+
+    // Try to compute the metadata size
+    ComputeSize( &iMetaDataBuf, 0 );
+
+    // check whether metadata size is available ( non zero)
+    if ( iMetaDataSize )
+        {
+        iState = ECollectData;              
+        }
+    
+    if ( iMetaDataBuf.Size() >= iMetaDataSize )
+        {
+        iState = EParseData;      
+        }
+    }   
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::ComputeSize
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::ComputeSize( TDesC8* aBuf, TInt aOffset )
+    {
+    if ( aBuf->Size() < ( aOffset + KID3v2HeaderLength ) )
+        {
+        iMetaDataSize = 0;
+        return;
+        }
+            
+    // calculate the size
+    for ( TInt i = 6; i < 10; i++ )
+        {
+        iMetaDataSize <<= 7;
+        iMetaDataSize |= (*aBuf)[i+aOffset] & 0x7f;
+        }
+    iMetaDataSize += KID3v2HeaderLength; // add the header for total size
+    
+    }   
+   
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::CollectMetaData
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::CollectMetaDataL( TDesC8* aBuf )
+    {
+    TUint8* ptr = const_cast<TUint8*> (aBuf->Ptr());
+    AppendBufferL( &iMetaDataBuf, ptr, aBuf->Size() );            
+    
+    if ( iMetaDataBuf.Size() >= iMetaDataSize )
+        {
+        iState = EParseData;      
+        }
+     }
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::CopyBufferL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::CopyBufferL(RBuf8* aDes, TUint8* aPtr, TInt aSize )
+    {
+     if ( aDes->MaxLength() < aSize)
+        {
+        aDes->ReAllocL( aSize );
+        }
+     aDes->Copy( aPtr, aSize );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMetaDataBufferAgg::AppendBufferL
+// -----------------------------------------------------------------------------
+//
+void CMetaDataBufferAgg::AppendBufferL(RBuf8* aDes, TUint8* aPtr, TInt aSize )
+    {
+    TInt size = aDes->Size();
+    if ( aDes->MaxLength() < aSize+size)
+        {
+        aDes->ReAllocL( aSize+size );
+        }
+     aDes->Append( aPtr, aSize );
+    }
+
+