srsf/sisrscontrollerplugin/src/silexicondb.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:29:17 +0100
branchRCL_3
changeset 19 e36f3802f733
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2004-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:  This class handles the storage and access of speaker independent
*               lexicons.  It is also responsible for allocating memory when
*               loading lexicons into the recognizer.
*
*/


// INCLUDE FILES
#include "silexicondb.h"
#include "rubydebug.h"

// CONSTANTS


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

// -----------------------------------------------------------------------------
// CSILexiconDB::CSILexiconDB
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSILexiconDB::CSILexiconDB( RDbNamedDatabase& aDatabase, 
                            RDbs& aDbSession,
                            TInt aDrive )
:	CSICommonDB(aDatabase, aDbSession, aDrive )
{
}

// -----------------------------------------------------------------------------
// CSILexiconDB::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSILexiconDB::ConstructL()
    {
    RUBY_DEBUG_BLOCK( "CSILexiconDB::ConstructL" );
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSILexiconDB* CSILexiconDB::NewL( RDbNamedDatabase& aDatabase, 
                                  RDbs& aDbSession,
                                  TInt aDrive )
    {
    RUBY_DEBUG_BLOCK( "CSILexiconDB::NewL" );
    CSILexiconDB* self 
        = new( ELeave ) CSILexiconDB( aDatabase, aDbSession, aDrive );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );	
    return self;
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::~CSILexiconDB
// Destructor
// -----------------------------------------------------------------------------
//
CSILexiconDB::~CSILexiconDB()
    {
    // Delete all elements of the array before deleting the array
    //	iLexiconArray.ResetAndDestroy();
    //	iLexiconArray.Close();
    RUBY_DEBUG0( "CSILexiconDB::~CSILexiconDB" );
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::CreateLexiconL
// Creates a new lexicon table in the database.
// -----------------------------------------------------------------------------
//
TSILexiconID CSILexiconDB::CreateLexiconL( TUid aClientUid )
    {
    RUBY_DEBUG_BLOCK( "CSILexiconDB::CreateLexiconL" );
    
    User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, sizeof( CSILexicon ) ) );
    
    // Generate a new Lexicon ID
    TSILexiconID lexiconID = STATIC_CAST(TSILexiconID,CreateNewIDL(KLexiconIdTable, KLexiconIdColumn, aClientUid ));
    
    // Construct the table name using the new lexicon ID
    TBuf<40> KLexiconName( KSILexiconTable );
    KLexiconName.AppendNumUC( lexiconID );
    RUBY_DEBUG1( "CSILexiconDB::CreateLexiconL lexicon ID: %i", lexiconID );
	
    
    // Create a table definition
    CDbColSet* columns = CDbColSet::NewLC();
    
    // add the columns  
    // 1) Binary data, 2) binary data size
    columns->AddL( TDbCol( KBinaryLexiconColumn, EDbColLongBinary ) );
    columns->AddL( TDbCol( KBinaryLexiconColumnSize, EDbColUint32 ) );
    
    // Create a table
    TInt err =iDb.CreateTable( KLexiconName, *columns );
    
    if ( err != KErrNone )
        {
        // Failed to create the table.
        // Need to release the new Lexicon ID and leave.
        ReleaseIdL( KLexiconIdTable, KLexiconIdColumn, lexiconID );
        User::Leave( err );
        }
    
    // cleanup the column set
    CleanupStack::PopAndDestroy( columns );
    // Construct the table name using the provided grammar ID
    // Declare a literal string to hold the SQL statement
    // SELECT KBinaryLexiconColumn , KBinaryLexiconColumn FROM  KLexiconName
    _LIT(KSQLSelect1,"select  ");	
    _LIT(KSQLSelect2," from  ");		
    TBuf<120> KSQLStatement;		
    KSQLStatement.Append(KSQLSelect1  );	
    KSQLStatement.Append(KBinaryLexiconColumn );
    KSQLStatement.Append(KNext);
    KSQLStatement.Append(KBinaryLexiconColumnSize );	
    KSQLStatement.Append(KSQLSelect2  );
    KSQLStatement.Append(KLexiconName); 
    
    // create a view on the database
    RDbView view;
    User::LeaveIfError(view.Prepare(iDb,TDbQuery(KSQLStatement,EDbCompareNormal)));
    User::LeaveIfError(view.EvaluateAll());
    
    // Get the structure of rowset
    CDbColSet* colSet = view.ColSetL(); 
    view.InsertL();
    view.PutL();
    
    
    // close the view
    view.Close();
    delete colSet; 
    
    // add an empty lexicon
    CSILexicon *aLexicon=CSILexicon::NewL(lexiconID);	
    CleanupStack::PushL(aLexicon);
    UpdateLexiconL(aClientUid,aLexicon);
    CleanupStack::PopAndDestroy(aLexicon);	
    
    iDbSession.FreeReservedSpace( iDrive );
    
    return lexiconID;
    }


// -----------------------------------------------------------------------------
// CSILexiconDB::UpdateLexiconL
// Inserts the externalized SI Lexicon into the specified grammar table.
// Save the Lexicon into the database
// -----------------------------------------------------------------------------
//
void CSILexiconDB::UpdateLexiconL( TUid aClientUid, 
								   CSILexicon *aSILexicon )
    {
    
    //	__UHEAP_MARK;
    TSILexiconID aLexiconID=aSILexicon->LexiconID();
    VerifyOwnershipL(aClientUid, KLexiconIdTable, KLexiconIndex, aLexiconID);
    
    // Construct the table name using the provided grammar ID
    // Declare a literal string to hold the SQL statement
    // SELECT KBinaryLexiconColumn , KBinaryLexiconColumn FROM  KLexiconName
    TBuf<40> KLexiconName(KSILexiconTable);
    KLexiconName.AppendNumUC(aLexiconID);	
    _LIT(KSQLSelect1,"select  ");	
    _LIT(KSQLSelect2," from  ");		
    TBuf<120> KSQLStatement;		
    KSQLStatement.Append(KSQLSelect1  );	
    KSQLStatement.Append(KBinaryLexiconColumn );
    KSQLStatement.Append(KNext);
    KSQLStatement.Append(KBinaryLexiconColumnSize );	
    KSQLStatement.Append(KSQLSelect2  );
    KSQLStatement.Append(KLexiconName); 
    
    // create a view on the database
    RDbView view;
    User::LeaveIfError(view.Prepare(iDb,TDbQuery(KSQLStatement,EDbCompareNormal)));
    User::LeaveIfError(view.EvaluateAll());
    
    // Get the structure of rowset
    CDbColSet* colSet = view.ColSetL(); 
    
    view.FirstL(); 
    view.UpdateL();
    
    
    // Externalize grammar
    CBufFlat* dataCopyBuffer = CBufFlat::NewL( 100 ); // 100 = expand 100 bytes
    CleanupStack::PushL(dataCopyBuffer);              // when the buffer is full
    //TPtr8 Buft((TUint8*) abuf,3,3);
    //dataCopyBuffer->InsertL(0,Buft);
    RBufWriteStream stream;
    stream.Open(*dataCopyBuffer);
    CleanupClosePushL(stream);
    aSILexicon->ExternalizeL(stream);
    CleanupStack::PopAndDestroy( &stream );
    
    TPtr8 aWriteBuf(dataCopyBuffer->Ptr(0));
    TInt BufSize =aWriteBuf.Size();
    
    // add binary buffer by Using the stream  
    RDbColWriteStream out;
    TDbColNo col = colSet->ColNo(KBinaryLexiconColumn); // Ordinal position of long column	
    out.OpenLC(view, col);
    out.WriteL(aWriteBuf);	
    out.Close();	
    CleanupStack::PopAndDestroy(); // out
    // add  size of the buffer
    col = colSet->ColNo(KBinaryLexiconColumnSize); // Ordinal position of  size	
    view.SetColL( col,BufSize); 
    
    view.PutL();
    
    // close the view
    view.Close();
    
    
    delete colSet; 
    CleanupStack::PopAndDestroy( dataCopyBuffer ); 
    //	__UHEAP_MARKEND;
    }

// -----------------------------------------------------------------------------
// CSIGrammarDB::GetNewID
// Get a new uniq ID 
// -----------------------------------------------------------------------------
TInt CSILexiconDB::GetNewID( RArray<TSIRuleID>& aMyIds ) 
    {
    RArray<TSIRuleID> myIDs = aMyIds;
    TInt Count = myIDs.Count();
    TInt id = 0;
    if ( Count == 0 ) 
        {
        id = 1; // empty ,first id will be 1
        }
    else
        { 
        // Find a unique Rulevariant ID
        myIDs.SortUnsigned();
        id = myIDs[myIDs.Count() - 1] + 1; //by default , the last one 
        for ( TInt i = 0; i < myIDs.Count(); i++ ) 
            {
            TInt index = i + 1; 
            TInt s = myIDs[i];
            if ( s > index ) 
                {
                id = index;
                break;
                }
            }
        }
    return id;
    }


// -----------------------------------------------------------------------------
// CSILexiconDB::CreateIDTableL
// Creates a new lexicon ID table in the database.
// -----------------------------------------------------------------------------
//
void CSILexiconDB::CreateIDTableL()
    {
    // Invoke function in the base class CSICommonDB.
    CSICommonDB::CreateIDTableL(KLexiconIdTable, KLexiconIdColumn, KLexiconIndex);
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::GetAllClientLexiconIDsL
// This function returns all Lexicon IDs owned by the specified client.
// -----------------------------------------------------------------------------
//
void CSILexiconDB::GetAllClientLexiconIDsL( TUid aClientUid,
										    RArray<TSILexiconID>& aLexiconIDs )
    {
    //	GetAllClientIDsL(KLexiconIdTable, KLexiconIdColumn, aClientUid, aLexiconIDs);
    RArray<TUint32> ix;
    ix.Reset();
    GetAllClientIDsL(KLexiconIdTable, KLexiconIdColumn, aClientUid, ix);
    for(TInt i=0;i<ix.Count();i++) 
        aLexiconIDs.Append(STATIC_CAST(TSILexiconID,ix[i]));
    ix.Close();
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::GetAllLexiconIDsL
// This function returns all Lexicon IDs in the database.
// -----------------------------------------------------------------------------
//
void CSILexiconDB::GetAllLexiconIDsL( RArray<TSILexiconID>& aLexiconIDs )
    {
    // This is a hack to get the id aligned to 4-byte boundary,
    // for some reason this does not happen in winscw build if 
    // TSILexiconID is taken from stack.
    TSILexiconID* id = new (ELeave) TSILexiconID;
    CleanupStack::PushL( id );
    
    //	GetAllIDsL(KLexiconIdTable, KLexiconIdColumn, aLexiconIDs);
    RArray<TUint32> ix;
    ix.Reset();
    GetAllIDsL(KLexiconIdTable, KLexiconIdColumn, ix);
    for(TInt i=0;i<ix.Count();i++) 
        {
        *id = STATIC_CAST( TSILexiconID, ix[i] );
        aLexiconIDs.Append( *id );
        }
    ix.Close();
    CleanupStack::PopAndDestroy( id );
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::GetAllPronunciationIDsL
// This function returns all Pronunciation IDs within the specified Lexicon.
// Lexicon have to be loaded 
// -----------------------------------------------------------------------------
//
void CSILexiconDB::GetAllPronunciationIDsL( TSILexiconID aLexiconID, RArray<TSIPronunciationID>& aPronunciationIDs )
    {
	CleanupClosePushL( aPronunciationIDs ); 
	
    // Construct the table name using the provided Lexicon ID
    TBuf<40> KLexiconName(KSILexiconTable);
    KLexiconName.AppendNumUC(aLexiconID);
    
    CSILexicon* newLexicon = LexiconL( aLexiconID) ;// Load the Lexicon from database	
    CleanupStack::PushL(newLexicon);
    
    TSIPronunciationID	aPronunciationID;
    for (TInt  i=0;i<newLexicon->Count();i++) {
        CSIPronunciation* aPronunciation=&(newLexicon->AtL(i));
        aPronunciationID=aPronunciation->PronunciationID();		
        User::LeaveIfError(aPronunciationIDs.Append(aPronunciationID));
        } 
    
    CleanupStack::PopAndDestroy(newLexicon); // newLexicon
    //	GetAllIDsL(KLexiconName, KPronunciationIDColumn, aPronunciationIDs);
    CleanupStack::Pop(); 
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::RemoveLexiconL
// Deletes a Lexicon table from the database.
// -----------------------------------------------------------------------------
//
void CSILexiconDB::RemoveLexiconL( TUid aClientUid,
								   TSILexiconID aLexiconID )
    {
    
    VerifyOwnershipL(aClientUid, KLexiconIdTable, KLexiconIndex, aLexiconID);
    
    
    /* Some times removing of corrupted lexicon fails because of this:
    TInt diskSpace = ( PronunciationCountL(aLexiconID) * sizeof( CSIPronunciation ) )
        + sizeof( CSILexicon );
    User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, diskSpace ) );
    */
    
    // Construct the table name using the provided Lexicon ID
    TBuf<40> KLexiconName(KSILexiconTable);
    KLexiconName.AppendNumUC(aLexiconID);
    
    TBuf<50> KSQLStatement;
    // Declare a literal string to hold the SQL statement
    // DROP TABLE KLexiconName
    _LIT(KSQLDelete1, "DROP TABLE ");
    
    KSQLStatement = KSQLDelete1;
    KSQLStatement.Append(KLexiconName);
    
    User::LeaveIfError(iDb.Execute(KSQLStatement));
    
    // Release the Lexicon ID
    ReleaseIdL(KLexiconIdTable, KLexiconIdColumn, aLexiconID);
    
    // Cancel free disk space request
    //iDbSession.FreeReservedSpace( iDrive );
    
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::PronunciationCountL
// Returns the number of Pronunciations in the specified Lexicon.
// -----------------------------------------------------------------------------
TInt CSILexiconDB::PronunciationCountL( TSILexiconID aLexiconID )
    {
    
    CSILexicon* newLexicon = LexiconL( aLexiconID) ;	
    CleanupStack::PushL(newLexicon);
    
    TInt PronunciationCount=newLexicon->Count();	 
    CleanupStack::PopAndDestroy(newLexicon); 	
    return PronunciationCount;

    }

// -----------------------------------------------------------------------------
// CSILexiconDB::IsPronunciationValidL
// Checks if the specified pronunciation exists in the specified loaded	.
// 
// -----------------------------------------------------------------------------
//
TBool CSILexiconDB::IsPronunciationValidL( TSILexiconID aLexiconID,
                                           TSIPronunciationID aPronunciationID )
    {
    CSILexicon* newLexicon = LexiconL( aLexiconID) ;		 
    CleanupStack::PushL(newLexicon);
    
    if (newLexicon->Find(aPronunciationID)==KErrNotFound) {
        CleanupStack::PopAndDestroy(newLexicon); // newLexicon
        return EFalse; 
        }
    else {
        CleanupStack::PopAndDestroy(newLexicon); // newLexicon
        return ETrue;	
        }
    }


// -----------------------------------------------------------------------------
// CSILexiconDB::ResetAndDestroy
// Deallocates the temporary memory containing the Lexicon object created with
// AllPronunciationsL.
// -----------------------------------------------------------------------------
//
void CSILexiconDB::ResetAndDestroy()
    {
    //	iLexiconArray.ResetAndDestroy();
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::RemovePronunciationL
// Deletes Pronunciation from the database.
// -----------------------------------------------------------------------------
//
void CSILexiconDB::RemovePronunciationL(  TUid aClientUid, 
                                        TSILexiconID aLexiconID,
                                        TSIPronunciationID aPronunciationID
                                        )
    {
    // Check the ownership first
    VerifyOwnershipL(aClientUid, KLexiconIdTable, KLexiconIndex, aLexiconID);
    
    CSILexicon* newLexicon = LexiconL( aLexiconID);		 
    CleanupStack::PushL(newLexicon);
    
    if (newLexicon->Find(aPronunciationID)==KErrNotFound)
        User::Leave(KErrNotFound);				 
    else  
        newLexicon->DeleteL(aPronunciationID);
    UpdateLexiconL(aClientUid  , newLexicon);
    CleanupStack::PopAndDestroy(newLexicon); // newLexicon
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::AddPronunciationL
// Add Pronunciation to the database.
// -----------------------------------------------------------------------------
//
TSIPronunciationID CSILexiconDB::AddPronunciationL( TUid aClientUid, 
                                                   TSILexiconID aLexiconID,
                                                   TDesC8& aPronunciationPr,
                                                   TSIModelBankID aModelBankID)
    {
    // Check the ownership first
    VerifyOwnershipL( aClientUid, KLexiconIdTable, KLexiconIndex, aLexiconID );
    
    CSILexicon* aLexicon = LexiconL( aLexiconID );
    CleanupStack::PushL( aLexicon );
    
    // existing myPronunciationID
    RArray<TSIPronunciationID> myPronunciationID;
    myPronunciationID.Reset();
    for( TInt i = 0; i < aLexicon->Count(); i++ )
        {
        CSIPronunciation* aPronunciation = &( aLexicon->AtL( i ) );
        myPronunciationID.Append( aPronunciation->PronunciationID() );
        }
    
    // Find a uniq new id 
    TSIPronunciationID aPronunciationID = GetNewID( myPronunciationID );
    myPronunciationID.Close();
    
    // add the  phoneme sequence  to the Pronunciation
    CSIPronunciation* pronunciation = CSIPronunciation::NewL( aPronunciationID, aModelBankID );
    CleanupStack::PushL( pronunciation );	
    pronunciation->SetPhonemeSequenceL( aPronunciationPr );
    aLexicon->AddL( pronunciation );
    CleanupStack::Pop( pronunciation ); // aPronunciation
    UpdateLexiconL( aClientUid,aLexicon );
    CleanupStack::PopAndDestroy( aLexicon ); // aLexicon
    return aPronunciationID;
    }

// -----------------------------------------------------------------------------
// CSILexiconDB::LexiconL
// Loads all pronunciations within the specified lexicon into a lexicon object
// -----------------------------------------------------------------------------
//
CSILexicon* CSILexiconDB::LexiconL( TSILexiconID aLexiconID )
    {
    
    // Construct the table name using the provided grammar ID
    // Construct the table name using the provided grammar ID
    // Declare a literal string to hold the SQL statement
    // SELECT KBinaryLexiconColumn , KBinaryLexiconColumn FROM  KLexiconName
    TBuf<40> KLexiconName(KSILexiconTable);
    KLexiconName.AppendNumUC(aLexiconID);
    // Create newLexicon object	
    CSILexicon* lexicon = CSILexicon::NewLC( aLexiconID );	
    _LIT(KSQLSelect1,"select  ");	
    _LIT(KSQLSelect2," from  ");
    TBuf<120> KSQLStatement;		
    KSQLStatement.Append(KSQLSelect1  );		
    KSQLStatement.Append(KBinaryLexiconColumn );
    KSQLStatement.Append(KNext);
    KSQLStatement.Append(KBinaryLexiconColumnSize );
    KSQLStatement.Append(KSQLSelect2  );
    KSQLStatement.Append(KLexiconName); 
    
    // create a view on the database
    RDbView view;
    CleanupClosePushL( view );
    
    User::LeaveIfError(view.Prepare(iDb,TDbQuery(KSQLStatement,EDbCompareNormal)));
    User::LeaveIfError(view.EvaluateAll());
    
    // Get the structure of the rowset 
    CDbColSet* colSet = view.ColSetL();
    CleanupStack::PushL( colSet );
    
    // iterate across the row set, one row only
    for (view.FirstL();view.AtRow();view.NextL())
        {
        
        // retrieve the row
        view.GetL();
        
        // first retrieve the size of binary package 
        TDbColNo col = colSet->ColNo(KBinaryLexiconColumnSize); // Ordinal position of long column 
        TInt32 size = view.ColUint32( col);
        
        TUint8* buf = new (ELeave) TUint8[size];		
        CleanupStack::PushL( buf);			
        TPtr8 readBuf( buf, size, size);
        CBufFlat* dataCopyBuffer = CBufFlat::NewL( 100 ); // 100 = expand 100 bytes
        CleanupStack::PushL( dataCopyBuffer );              // when the buffer is full
        
        RBufReadStream stream;
        CleanupClosePushL( stream );
        stream.Open(*dataCopyBuffer);
        
        // and a stream for long columns
        RDbColReadStream in;
        CleanupClosePushL( in );
        col = colSet->ColNo(KBinaryLexiconColumn); // Ordinal position of long column 
        
        
        in.OpenLC(view, col);
        in.ReadL(readBuf, view.ColLength(col));
        dataCopyBuffer->InsertL(0,readBuf);
        lexicon->InternalizeL( stream );
        
        CleanupStack::PopAndDestroy( col );
        CleanupStack::PopAndDestroy( &in );
        CleanupStack::PopAndDestroy( &stream ); 
        CleanupStack::PopAndDestroy( dataCopyBuffer );
        CleanupStack::PopAndDestroy( buf );
        }
    
    CleanupStack::PopAndDestroy( colSet );
    CleanupStack::PopAndDestroy( &view );
    

 
    // Cleanup lexicon
    CleanupStack::Pop( lexicon );
    return lexicon;
    }

//  End of File