/*
* Copyright (c) 2004-2006 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: Serialization functions for CSIGrammar and CSILexicon
*
*/
// INCLUDE FILES
#include "nsssidataserialize.h"
#include <s32mem.h> // RBuf[Read/Write]Stream
// LOCAL CONSTANTS AND MACROS
const TUint32 KNibble16Limit = 0xffff;
const TUint32 KNibble4Limit = 0xf;
// LOCAL FUNCTION PROTOTYPES
void Externalize32bitArrayL( RWriteStream& aStream, RArray<TUint32>& aArray );
void Internalize32bitArrayL( RReadStream& aStream, RArray<TUint32>& aArray );
TInt IndexOrderForPhonemes( const TLexiconPhoneme& p1, const TLexiconPhoneme& p2 );
TInt StringOrderForPhonemes( const TLexiconPhoneme& p1, const TLexiconPhoneme& p2 );
// ============================= LOCAL FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// Externalize32bitArrayL
// Writes an RArray with 32-bit entries to the stream.
// Returns: None
// -----------------------------------------------------------------------------
//
void Externalize32bitArrayL(
RWriteStream& aStream, // The stream where to store the array
RArray<TUint32>& aArray ) // The array; the entries must be 32-bit.
{
TInt count = aArray.Count();
aStream.WriteInt32L( count );
if ( count > 0 )
{
TInt* startPtr = (TInt*)&aArray[0];
aStream.WriteL( (TUint8*)startPtr, sizeof(TInt) * count );
}
}
// -----------------------------------------------------------------------------
// Internalize32bitArrayL
// Reads an array from the stream.
// Returns: None
// -----------------------------------------------------------------------------
//
void Internalize32bitArrayL(
RReadStream& aStream, // The stream to read from
RArray<TUint32>& aArray ) // The array to be populated
{
TInt count = aStream.ReadInt32L();
TInt err = KErrNone;
for ( TInt k( 0 ); k < count; k++ )
{
TInt value = aStream.ReadInt32L();
err |= aArray.Append( value );
}
User::LeaveIfError( err );
}
// -----------------------------------------------------------------------------
// IndexOrderForPhonemes
//
// -----------------------------------------------------------------------------
//
TInt IndexOrderForPhonemes( const TLexiconPhoneme& p1, const TLexiconPhoneme& p2 )
{
return( p1.iIndex - p2.iIndex );
}
// -----------------------------------------------------------------------------
// StringOrderForPhonemes
//
// -----------------------------------------------------------------------------
//
TInt StringOrderForPhonemes( const TLexiconPhoneme& p1, const TLexiconPhoneme& p2 )
{
return( p1.iPhoneme.Compare( p2.iPhoneme ) );
}
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// Implementation of CSILexiconSerializer starts from here.
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
// CSILexiconSerializer::CSILexiconSerializer
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSILexiconSerializer::CSILexiconSerializer()
{
iPronunIDs = NULL;
iModelBankIDs = NULL;
iParamBuf = NULL;
iCount = 0;
iLexiconID = 0; // !!!! Change to KInvalidLexiconID.
}
// -----------------------------------------------------------------------------
// CSILexiconSerializer::~CSILexiconSerializer
// Destructor.
// -----------------------------------------------------------------------------
//
CSILexiconSerializer::~CSILexiconSerializer()
{
iPronunciations.ResetAndDestroy();
iIndexPronuns.ResetAndDestroy();
iConversionTable.Close();
delete iPronunIDs;
delete iModelBankIDs;
delete iParamBuf;
}
// -----------------------------------------------------------------------------
// CSILexiconSerializer::NextPhonemeL
// Stores the next phoneme to phonemeBuf and increases the cursor.
// Returns true if there are still more phonemes.
// -----------------------------------------------------------------------------
//
bool CSILexiconSerializer::NextPhonemeL(
TDes8& phonemeBuf,
const TDesC8& phonemeSeq,
TInt& aReadIterator )
{
TInt length = phonemeSeq.Length();
// Out of phonemes?
if ( length == aReadIterator )
{
return( false );
}
// Cut those phonemes away, which have been processed already.
TPtrC8 unfinishedPhonemes = phonemeSeq.Right( length - aReadIterator );
// Make SeparatorLoc point to the end of the next phoneme.
TInt separatorLoc = unfinishedPhonemes.Locate( KPhonemeSeparator );
// Phoneme length is from [start of unprocessed string] to [separator]...
TInt phonemeLength = separatorLoc;
// ...unless we're dealing with the last phoneme. Then
// phonemeLength is from [start of unprocessed string] to [end of string].
if ( separatorLoc == KErrNotFound )
phonemeLength = length - aReadIterator;
// Check that the phoneme is not too long.
if ( phonemeLength > KMaxPhonemeLength )
{
User::Leave( KErrArgument );
}
if ( phonemeLength == 0 )
{
return( false );
}
// Copy
phonemeBuf.Copy( unfinishedPhonemes.Ptr(), phonemeLength );
// Update iterator
aReadIterator += phonemeLength; // The phoneme
if ( aReadIterator < length ) // The separator
{
aReadIterator++;
}
return( true );
}
// -----------------------------------------------------------------------------
// CSILexiconSerializer::SavePronunciationL
// Converts the ASCII phoneme strings to internal index strings.
// -----------------------------------------------------------------------------
//
void CSILexiconSerializer::SavePronunciationL(CSIPronunciation* aPronun)
{
TLinearOrder<TLexiconPhoneme> order( StringOrderForPhonemes );
// This phoneme is used for searching
TLexiconPhoneme searchPhoneme;
TDes8& phonemeBuf = searchPhoneme.iPhoneme;
const TDesC8& phonemeSeq = aPronun->PhonemeSequence();
HBufC8* indexPronun = HBufC8::NewLC( phonemeSeq.Length() );
TInt phonemeReadIter = 0;
while( NextPhonemeL( phonemeBuf, phonemeSeq, phonemeReadIter ) )
{
// Search the phoneme from conversion table.
TInt loc = iConversionTable.FindInOrder( searchPhoneme, order );
// Not found? Add the phoneme as a new phoneme.
if ( loc == KErrNotFound )
{
searchPhoneme.iIndex = iConversionTable.Count();
User::LeaveIfError(
iConversionTable.InsertInOrder( searchPhoneme, order )
);
// Can't fail: the phoneme has just been added.
loc = iConversionTable.FindInOrder( searchPhoneme, order );
// Make sure that phoneme count fits in TUint8
if ( searchPhoneme.iIndex >= 250 )
{
User::Leave( KErrOverflow );
}
}
// Phoneme to index
// Case to TUint8 is safe - Checked 10 lines earlier.
TUint8 index = (TUint8)iConversionTable[ loc ].iIndex;
indexPronun->Des().Append( index );
}
// Add pronunciation to the list of "index-pronunciations"
User::LeaveIfError( iIndexPronuns.Append( indexPronun ) );
CleanupStack::Pop( indexPronun );
}
// -----------------------------------------------------------------------------
// CSILexiconSerializer::Index2PhonemeLC
// Restores an internal index string into ASCII phonemes.
// -----------------------------------------------------------------------------
//
HBufC8* CSILexiconSerializer::Index2PhonemeLC(const TDesC8& aIndexSeq)
{
TLinearOrder<TLexiconPhoneme> order( IndexOrderForPhonemes );
iConversionTable.Sort( order );
TInt length = 0;
TInt k( 0 );
for( k = 0; k < aIndexSeq.Length(); k++ )
{
TInt index = aIndexSeq[ k ];
length += iConversionTable[ index ].iPhoneme.Length();
length++; // Separator ('-')
}
HBufC8* buf = HBufC8::NewLC( length );
TPtr8 ptr = buf->Des();
TInt lastK = aIndexSeq.Length() -1; // Index of the last character
for( k = 0; k < aIndexSeq.Length(); k++ )
{
TInt index = aIndexSeq[ k ];
ptr.Append( iConversionTable[ index ].iPhoneme );
// Add separator, except for the last phoneme
if ( k != lastK )
{
ptr.Append( KPhonemeSeparator );
}
}
return( buf );
}
// -----------------------------------------------------------------------------
// CSILexiconSerializer::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSILexiconSerializer* CSILexiconSerializer::NewLC( const CSILexicon& aLexicon )
{
CSILexiconSerializer* me = new (ELeave) CSILexiconSerializer;
CleanupStack::PushL( me );
me->ConstructL( aLexicon );
return( me );
}
// -----------------------------------------------------------------------------
// CSILexiconSerializer::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSILexiconSerializer* CSILexiconSerializer::NewLC( RReadStream& aStream )
{
CSILexiconSerializer* me = new (ELeave) CSILexiconSerializer;
CleanupStack::PushL( me );
me->InternalizeL( aStream );
return( me );
}
// -----------------------------------------------------------------------------
// CSILexiconSerializer::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSILexiconSerializer::ConstructL( const CSILexicon& aLexicon )
{
iLexiconID = aLexicon.LexiconID();
iCount = aLexicon.Count();
iParamBuf = CBufFlat::NewL( 100 ); // Grow in 100 byte doses
RArray<TSIModelBankID> modelBankIDs;
RArray<TSIPronunciationID> pronunIDs;
CleanupClosePushL( modelBankIDs );
CleanupClosePushL( pronunIDs );
RBufWriteStream paramStream;
paramStream.Open( *iParamBuf );
CleanupClosePushL( paramStream );
// In serialization format, the 5 types of data in pronunciations
// are put to 4 piles. Then, the common properties of the data is exploited.
for ( TInt k = 0; k < aLexicon.Count(); k++ )
{
CSIPronunciation* pronun = &aLexicon.AtL( k );
// 4 types of pronunciation data
TInt err = KErrNone;
// This is a hack to get the modelid aligned to 4-byte boundary,
// for some reason this does not happen in winscw build if
// TSIModelBankID is taken from stack.
TSIModelBankID* modelid = new (ELeave) TSIModelBankID;
*modelid = pronun->ModelBankID();
err |= modelBankIDs.Append( *modelid );
// Delete temporary modelid
delete modelid;
err |= pronunIDs.Append( pronun->PronunciationID() );
User::LeaveIfError( err );
SavePronunciationL( pronun );
// Parameters
pronun->CSIParameters::ExternalizeL( paramStream );
}
// Code the piled values
// Casts are safe, as all variables are 32-bit (they are just called
// with many different names - int, unsigned long, unsigned int)
iPronunIDs = CNibble16Coder::NewL( pronunIDs );
iModelBankIDs = CRLECoder::NewL( modelBankIDs );
CleanupStack::PopAndDestroy( ¶mStream );
CleanupStack::PopAndDestroy( 2 ); // Close the RArrays
}
// -----------------------------------------------------------------------------
// CSILexiconSerializer::ExternalizeL
// Stores the object to the stream.
// -----------------------------------------------------------------------------
//
void CSILexiconSerializer::ExternalizeL( RWriteStream& aStream )
{
aStream.WriteInt32L( KBinaryLexiconID );
aStream.WriteInt32L( iLexiconID );
aStream.WriteInt32L( iCount );
// Write model bank IDs.
iModelBankIDs->ExternalizeL( aStream );
// Write pronunciation IDs
iPronunIDs->ExternalizeL( aStream );
// Write pronunciations (converted from phonemes to indices)
aStream.WriteInt32L( iIndexPronuns.Count() );
TInt k( 0 );
for ( k = 0; k < iIndexPronuns.Count(); k++ )
{
HBufC8* pronun = iIndexPronuns[ k ];
// There is no fixed limit on the length of a phoneme sequence.
// It's not even guaranteed that the length fits in 32 bits, damnit!
if ( pronun->Length() > 64000 )
{
User::Leave( KErrNotSupported );
}
aStream.WriteUint16L( pronun->Length() );
aStream.WriteL( pronun->Ptr(), pronun->Length() );
}
// Write parameters
aStream.WriteInt32L( iParamBuf->Size() );
aStream.WriteL( iParamBuf->Ptr(0) );
// Write phoneme<->index conversion table
aStream.WriteInt32L( iConversionTable.Count() );
for ( k = 0; k < iConversionTable.Count(); k++ )
{
aStream.WriteL( (TUint8*)&iConversionTable[k],
sizeof( TLexiconPhoneme ) );
}
// For corruption checking
aStream.WriteInt32L( KBinaryLexiconID );
}
// -----------------------------------------------------------------------------
// CSILexiconSerializer::InternalizeL
// Restores the object from a stream
// -----------------------------------------------------------------------------
//
void CSILexiconSerializer::InternalizeL(RReadStream& aStream)
{
if ( aStream.ReadInt32L() != KBinaryLexiconID )
User::Leave( KErrArgument );
iLexiconID = (TSILexiconID)aStream.ReadUint32L();
iCount = aStream.ReadInt32L();
// Read model bank IDs
iModelBankIDs = CRLECoder::NewL( aStream );
// Read pronunciation IDs
iPronunIDs = CNibble16Coder::NewL( aStream );
// Read pronunciations (converted from phonemes to indices)
TInt indexCount = aStream.ReadInt32L();
if ( indexCount != iCount )
{
User::Leave( KErrCorrupt );
}
TInt k( 0 );
for ( k = 0; k < indexCount; k++ )
{
HBufC8* pronun = 0;
TUint16 length = aStream.ReadUint16L();
pronun = HBufC8::NewLC( length );
TPtr8 pronunPtr = pronun->Des();
aStream.ReadL( pronunPtr, length );
User::LeaveIfError( iIndexPronuns.Append( pronun ) );
CleanupStack::Pop( pronun );
}
// Read parameters
TInt size = aStream.ReadInt32L();
iParamBuf = CBufFlat::NewL( size+4 );
iParamBuf->ExpandL( 0, size );
TPtr8 paramBufPtr = iParamBuf->Ptr(0);
aStream.ReadL( paramBufPtr, size );
// Read phoneme<->index conversion table
TInt conversionCount = aStream.ReadInt32L();
for ( k = 0; k < conversionCount; k++ )
{
TLexiconPhoneme lexiconPhoneme;
aStream.ReadL( (TUint8*)&lexiconPhoneme,
sizeof( TLexiconPhoneme ) );
User::LeaveIfError( iConversionTable.Append( lexiconPhoneme ) );
}
// For corruption checking
if ( aStream.ReadInt32L() != KBinaryLexiconID )
{
User::Leave( KErrCorrupt );
}
}
// -----------------------------------------------------------------------------
// CSILexiconSerializer::RestoreL
// Populates CSILexicon with the newly internalized data.
// -----------------------------------------------------------------------------
//
void CSILexiconSerializer::RestoreL( CSILexicon& aLexicon, TSILexiconID& aLexiconID )
{
if ( aLexicon.Count() > 0 )
{
User::Leave( KErrInUse );
}
TSIModelBankID modelBankID = 0;
TSIPronunciationID pronunID = 0;
RBufReadStream paramStream;
paramStream.Open( *iParamBuf );
CleanupClosePushL( paramStream );
iModelBankIDs->DecodeReset();
iPronunIDs->DecodeReset();
TInt iterPronunPos = 0;
for ( TInt pronunK = 0; pronunK < iCount; pronunK++ )
{
modelBankID = iModelBankIDs->NextL();
pronunID = iPronunIDs->NextL();
CSIPronunciation* pronun
= CSIPronunciation::NewLC( pronunID, modelBankID );
HBufC8* indexSequence = iIndexPronuns[ iterPronunPos ];
iterPronunPos++;
HBufC8* phonemeSequence = Index2PhonemeLC( *indexSequence );
pronun->SetPhonemeSequenceL( *phonemeSequence );
CleanupStack::PopAndDestroy( phonemeSequence );
pronun->CSIParameters::InternalizeL( paramStream );
aLexicon.AddL( pronun );
CleanupStack::Pop( pronun );
}
CleanupStack::PopAndDestroy( ¶mStream );
// LexiconID can't be written to CSILexicon with public API.
aLexiconID = iLexiconID;
}
// -----------------------------------------------------------------------------
// Implementation of CSIGrammarSerializer starts from here.
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
// CSIGrammarSerializer::CSIGrammarSerializer
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSIGrammarSerializer::CSIGrammarSerializer()
{
iGrammarID = KInvalidGrammarID;
iCount = 0;
iRuleIDs = NULL;
iRuleVariantCounts = NULL;
iRuleVariantIDs = NULL;
iRuleVariantLexiconIDs = NULL;
iRuleVariantLanguages = NULL;
iPronunIDSeqLengths = NULL;
iPronunIDSequences = NULL;
iParamBuf = NULL;
}
// -----------------------------------------------------------------------------
// CSIGrammarSerializer::~CSIGrammarSerializer
// Destructor.
// -----------------------------------------------------------------------------
//
CSIGrammarSerializer::~CSIGrammarSerializer()
{
delete iRuleIDs;
delete iRuleVariantCounts;
delete iRuleVariantIDs;
delete iRuleVariantLexiconIDs;
delete iRuleVariantLanguages;
delete iPronunIDSeqLengths;
delete iPronunIDSequences;
delete iParamBuf;
}
// -----------------------------------------------------------------------------
// CSIGrammarSerializer::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSIGrammarSerializer* CSIGrammarSerializer::NewLC( const CSIGrammar& aGrammar )
{
CSIGrammarSerializer* me = new (ELeave) CSIGrammarSerializer();
CleanupStack::PushL( me );
me->ConstructL( aGrammar );
return( me );
}
// -----------------------------------------------------------------------------
// CSIGrammarSerializer::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSIGrammarSerializer::ConstructL( const CSIGrammar& aGrammar )
{
iParamBuf = CBufFlat::NewL( 100 ); // Grow in 100 byte doses
RBufWriteStream paramStream;
paramStream.Open( *iParamBuf );
CleanupClosePushL( paramStream ); // Cleanp stack: param stream
RArray<TSIRuleID> ruleIDs;
RArray<TUint32> ruleVariantCounts;
RArray<TUint32> ruleVariantIDs;
RArray<TSILexiconID> ruleVariantLexiconIDs;
RArray<TUint32> ruleVariantLanguages;
RArray<TUint32> pronunIDSeqLengths;
RArray<TSIPronunciationID> pronunIDSequences;
CleanupClosePushL( ruleIDs );
CleanupClosePushL( ruleVariantCounts );
CleanupClosePushL( ruleVariantIDs );
CleanupClosePushL( ruleVariantLexiconIDs );
CleanupClosePushL( ruleVariantLanguages );
CleanupClosePushL( pronunIDSeqLengths );
CleanupClosePushL( pronunIDSequences ); // Cleanup stack: param stream, 7 tmp arrays
TInt err = KErrNone;
// Pile the data according to type (8 types)
for ( TInt ruleK( 0 ); ruleK < aGrammar.Count(); ruleK++ )
{
CSIRule& rule = aGrammar.AtL( ruleK );
err |= ruleIDs.Append( rule.RuleID() );
err |= ruleVariantCounts.Append( rule.Count() );
for ( TInt variantK( 0 ); variantK < rule.Count(); variantK++ )
{
CSIRuleVariant& variant = rule.AtL( variantK );
err |= ruleVariantIDs.Append( variant.RuleVariantID() );
// This is a hack to get the lexid aligned to 4-byte boundary,
// for some reason this does not happen in winscw build if
// TSILexiconID is taken from stack.
TSILexiconID* lexid = new (ELeave) TSILexiconID;
*lexid = variant.LexiconID();
err |= ruleVariantLexiconIDs.Append( *lexid );
delete lexid;
err |= ruleVariantLanguages.Append( variant.Language() );
TSIPronunciationIDSequence seq;
CleanupClosePushL( seq ); // Cleanup stack: param stream, 7 tmp arrays, seq
variant.GetPronunciationIDsL( seq );
err |= pronunIDSeqLengths.Append( seq.Count() );
for ( TInt k( 0 ); k < seq.Count(); k++ )
{
err |= pronunIDSequences.Append( seq[k] );
}
CleanupStack::PopAndDestroy( &seq );
// Cleanup stack: param stream, 7 tmp arrays
// Store parameters to a buffer.
variant.ExternalizeL( paramStream );
}
User::LeaveIfError( err );
}
// Code the arrays
iGrammarID = aGrammar.GrammarID();
iCount = aGrammar.Count();
iRuleIDs = CNibble16Coder::NewL( ruleIDs );
iRuleVariantCounts = CNibble4Coder::NewL( ruleVariantCounts );
iRuleVariantIDs = CNibble4Coder::NewL( ruleVariantIDs );
iRuleVariantLexiconIDs = CRLECoder::NewL( ruleVariantLexiconIDs );
// Cast is safe, since TLanguage is 32-bit
iRuleVariantLanguages = CNibble4Coder::NewL( ruleVariantLanguages );
iPronunIDSeqLengths = CNibble4Coder::NewL( pronunIDSeqLengths );
iPronunIDSequences = CNibble16Coder::NewL( pronunIDSequences );
CleanupStack::PopAndDestroy( 7 ); // Destory 7 tmp arrays
CleanupStack::PopAndDestroy( ¶mStream ); // Destroy parameter stream
}
// -----------------------------------------------------------------------------
// CSIGrammarSerializer::ExternalizeL
// Stores the object to the stream.
// -----------------------------------------------------------------------------
//
void CSIGrammarSerializer::ExternalizeL( RWriteStream& aStream )
{
aStream.WriteUint32L( ( TUint32 ) KBinaryGrammarID );
aStream.WriteUint32L( iGrammarID );
aStream.WriteUint32L( iCount );
iRuleIDs ->ExternalizeL( aStream );
iRuleVariantCounts ->ExternalizeL( aStream );
iRuleVariantIDs ->ExternalizeL( aStream );
iRuleVariantLexiconIDs->ExternalizeL( aStream );
iRuleVariantLanguages ->ExternalizeL( aStream );
iPronunIDSeqLengths ->ExternalizeL( aStream );
iPronunIDSequences ->ExternalizeL( aStream );
aStream.WriteInt32L( iParamBuf->Size() );
aStream.WriteL( iParamBuf->Ptr(0) );
aStream.WriteUint32L( ( TUint32 ) KBinaryGrammarID );
}
// -----------------------------------------------------------------------------
// CSIGrammarSerializer::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSIGrammarSerializer* CSIGrammarSerializer::NewLC(RReadStream& aStream)
{
CSIGrammarSerializer* me = new (ELeave) CSIGrammarSerializer();
CleanupStack::PushL( me );
me->ConstructL( aStream );
return( me );
}
// -----------------------------------------------------------------------------
// CSIGrammarSerializer::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSIGrammarSerializer::ConstructL( RReadStream& aStream )
{
if ( aStream.ReadInt32L() != KBinaryGrammarID )
{
User::Leave( KErrCorrupt );
}
iGrammarID = (TSIGrammarID)aStream.ReadUint32L();
iCount = aStream.ReadUint32L();
iRuleIDs = CNibble16Coder::NewL( aStream );
iRuleVariantCounts = CNibble4Coder::NewL( aStream );
iRuleVariantIDs = CNibble4Coder::NewL( aStream );
iRuleVariantLexiconIDs= CRLECoder::NewL( aStream );
iRuleVariantLanguages = CNibble4Coder::NewL( aStream );
iPronunIDSeqLengths = CNibble4Coder::NewL( aStream );
iPronunIDSequences = CNibble16Coder::NewL( aStream );
TInt32 paramSize = aStream.ReadInt32L();
iParamBuf = CBufFlat::NewL( paramSize + 4 );
iParamBuf->ExpandL( 0, paramSize );
TPtr8 paramBufPtr = iParamBuf->Ptr(0);
aStream.ReadL( paramBufPtr, paramSize );
if ( aStream.ReadInt32L() != KBinaryGrammarID )
{
User::Leave( KErrCorrupt );
}
}
// -----------------------------------------------------------------------------
// CSIGrammarSerializer::RestoreL
// Populates the CSIGrammar with newly internalized data.
// -----------------------------------------------------------------------------
//
void CSIGrammarSerializer::RestoreL( CSIGrammar& aGrammar, TSIGrammarID& aGrammarID )
{
if ( aGrammar.Count() != 0 )
{
User::Leave( KErrInUse );
}
aGrammarID = iGrammarID;
TBool ready = iRuleIDs && iRuleVariantCounts && iRuleVariantIDs &&
iRuleVariantLexiconIDs && iRuleVariantLanguages &&
iPronunIDSeqLengths && iPronunIDSequences;
if ( !ready )
{
User::Leave( KErrNotReady );
}
iRuleIDs->DecodeReset();
iRuleVariantCounts->DecodeReset();
iRuleVariantIDs->DecodeReset();
iRuleVariantLexiconIDs->DecodeReset();
iRuleVariantLanguages->DecodeReset();
iPronunIDSeqLengths->DecodeReset();
iPronunIDSequences->DecodeReset();
RBufReadStream paramStream;
CleanupClosePushL( paramStream );
paramStream.Open( *iParamBuf );
for ( TInt ruleK( 0 ); ruleK < iCount; ruleK++ )
{
CSIRule* rule = CSIRule::NewLC( iRuleIDs->NextL() );
TInt ruleVariantCount = iRuleVariantCounts->NextL();
for ( TInt variantK( 0 ); variantK < ruleVariantCount; variantK++ )
{
CSIRuleVariant* variant = CSIRuleVariant::NewLC(
(TSIRuleVariantID)iRuleVariantIDs->NextL(),
iRuleVariantLexiconIDs->NextL()
);
variant->SetLanguage(
(enum TLanguage)iRuleVariantLanguages->NextL() );
RArray<TSIPronunciationID> pronunIDSeq;
CleanupClosePushL( pronunIDSeq );
TInt seqLength = iPronunIDSeqLengths->NextL();
for ( TInt pronunIdK( 0 ); pronunIdK < seqLength; pronunIdK++ )
{
TInt err = pronunIDSeq.Append( iPronunIDSequences->NextL() );
User::LeaveIfError( err );
}
variant->SetPronunciationIDsL( pronunIDSeq );
CleanupStack::PopAndDestroy( &pronunIDSeq );
variant->CSIParameters::InternalizeL( paramStream );
rule->AddL( variant );
CleanupStack::Pop( variant );
}
aGrammar.AddL( rule );
CleanupStack::Pop( rule );
}
CleanupStack::PopAndDestroy( ¶mStream );
}
// -----------------------------------------------------------------------------
// Implementation of CNibble16Coder starts from here.
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
// CNibble16Coder::CNibble16Coder
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CNibble16Coder::CNibble16Coder()
: iMainArray(50),
iOverflowArray(10)
{
DecodeReset();
}
// -----------------------------------------------------------------------------
// CNibble16Coder::NewL
// Two-phased constructor. Encodes the values given as the argument.
// -----------------------------------------------------------------------------
//
CNibble16Coder* CNibble16Coder::NewL( const RArray<TUint32>& aPlainArray )
{
CNibble16Coder* me = new (ELeave) CNibble16Coder;
CleanupStack::PushL( me );
TInt count = aPlainArray.Count();;
TInt sizeNeeded = (count+1) / 2;
// Grow the array to be big enough
TInt k( 0 );
for ( k = 0; k < sizeNeeded; k++ )
{
User::LeaveIfError( me->iMainArray.Append( 0xffffffff ) );
}
TUint16* storagePtr = 0;
if ( count > 0 )
{
storagePtr = (TUint16*)&me->iMainArray[0];
}
for( k = 0; k < count; k++ )
{
TSIPronunciationID id = aPlainArray[ k ];
TBool overflow = false;
// If the 32-bit value doesn't fit to 16 bits:
// * Put overflow sign to main array
// * Put the real ID to overflow array
if ( id >= KNibble16Limit )
{
overflow = true;
id = KNibble16Limit;
}
// Write to the main array
// ([overflow sign] OR [id, which fits to 16 bits])
*(storagePtr++) = (TUint16)id;
// If it didn't fit to 16 bits, save it to the overflow array.
if ( overflow )
{
TInt err = me->iOverflowArray.Append( aPlainArray[k] );
User::LeaveIfError( err );
}
}
CleanupStack::Pop( me );
return( me );
}
// -----------------------------------------------------------------------------
// CNibble16Coder::NewL
// Two-phased constructor. Internalizes an array from stream.
// -----------------------------------------------------------------------------
//
CNibble16Coder* CNibble16Coder::NewL( RReadStream& aStream )
{
CNibble16Coder* me = new (ELeave) CNibble16Coder;
CleanupStack::PushL( me );
if ( aStream.ReadInt32L() != KBinaryNibble16ID )
{
User::Leave( KErrCorrupt );
}
Internalize32bitArrayL( aStream, me->iMainArray );
Internalize32bitArrayL( aStream, me->iOverflowArray );
CleanupStack::Pop( me );
return( me );
}
// -----------------------------------------------------------------------------
// CNibble16Coder::~CNibble16Coder
// Destructor
// -----------------------------------------------------------------------------
//
CNibble16Coder::~CNibble16Coder()
{
iMainArray.Close();
iOverflowArray.Close();
}
// -----------------------------------------------------------------------------
// CNibble16Coder::DecodeReset
// Moves cursor to the beginning of the array.
// -----------------------------------------------------------------------------
//
void CNibble16Coder::DecodeReset()
{
iPosition = 0;
iOverflowPos = 0;
}
// -----------------------------------------------------------------------------
// CNibble16Coder::NextL
// Returns a value in the array and moves the cursor forward.
// -----------------------------------------------------------------------------
//
TUint32 CNibble16Coder::NextL()
{
if ( iPosition >= 2*iMainArray.Count() )
User::Leave( KErrOverflow );
TUint16* storagePtr = (TUint16*)&iMainArray[0];
// Get the [pronunciation ID] OR [overflow sign] from main array.
TSIPronunciationID id = storagePtr[ iPosition ];
// It was overflow sign; get whole 32-bit ID from overflow array
if ( id == KNibble16Limit ) // It was pronunciation ID
{
if ( iOverflowPos == iOverflowArray.Count() )
{
User::Leave( KErrOverflow );
}
id = iOverflowArray[ iOverflowPos ];
iOverflowPos++;
}
// Update iterator
iPosition++;
return( id );
}
// -----------------------------------------------------------------------------
// CNibble16Coder::ExternalizeL
// Externalizes the array into a stream.
// -----------------------------------------------------------------------------
//
void CNibble16Coder::ExternalizeL( RWriteStream& aStream )
{
aStream.WriteInt32L( KBinaryNibble16ID );
Externalize32bitArrayL( aStream, iMainArray );
Externalize32bitArrayL( aStream, iOverflowArray );
}
// -----------------------------------------------------------------------------
// Implementation of CNibble4Coder starts from here.
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
// CNibble4Coder::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CNibble4Coder* CNibble4Coder::NewL( const RArray<TUint32>& aPlainArray )
{
CNibble4Coder* me = new (ELeave) CNibble4Coder;
CleanupStack::PushL( me );
me->DecodeReset();
TInt count = aPlainArray.Count();
for ( TInt k( 0 ); k < count; k++ )
{
TUint compactValue = aPlainArray[ k ];
TBool overflow = EFalse;
// If the value does not fit to 4 bytes, put an overflow sign to main
// array, and save the value to a separate overflow array.
if ( compactValue >= KNibble4Limit )
{
compactValue = KNibble4Limit;
overflow = true;
}
// Save the compact value
if ( me->iSlot == 0 )
{
User::LeaveIfError( me->iMainArray.Append( compactValue ) );
me->iSlot++;
}
else{
// We save 4-bit values to 32-bit variable. So, there are 8 slots
// in each 32-bit entry.
// Shift the value to correct slot.
// Earlier, we have made sure, that compactValue < 16.
compactValue = compactValue << (4 * me->iSlot);
// Put it to the array.
me->iMainArray[ me->iPosition ]
= compactValue | me->iMainArray[ me->iPosition ];
// Update iterator
me->iSlot++;
if ( me->iSlot == 8 )
{
me->iPosition++;
me->iSlot = 0;
}
}
// If the value didn't fit to 4 bits, save it to 32-bit overflow array.
if ( overflow )
{
TInt ret = me->iOverflowArray.Append( aPlainArray[ k ] );
User::LeaveIfError( ret );
}
}
// If the number of entries was not divisible by 8, we have
// uninitialized slots in the end. Initialize them with 0xf.
// If the decoder finds one of these 0xf's, it goes to overflow array,
// notices that all entries in the overflow array have been processed,
// and leaves.
if ( me->iSlot != 0 )
{
TUint unusedValue = 0xffffffff;
unusedValue = unusedValue << (4 * me->iSlot);
me->iMainArray[ me->iPosition ]
= unusedValue | me->iMainArray[ me->iPosition ];
}
me->DecodeReset();
CleanupStack::Pop( me );
return me;
}
// -----------------------------------------------------------------------------
// CNibble4Coder::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CNibble4Coder* CNibble4Coder::NewL( RReadStream& aStream )
{
CNibble4Coder* me = new (ELeave) CNibble4Coder;
CleanupStack::PushL( me );
me->DecodeReset();
if ( aStream.ReadInt32L() != KBinaryNibble4ID )
{
User::Leave( KErrCorrupt );
}
Internalize32bitArrayL( aStream, me->iMainArray );
Internalize32bitArrayL( aStream, me->iOverflowArray );
CleanupStack::Pop( me );
return( me );
}
// -----------------------------------------------------------------------------
// CNibble4Coder::CNibble4Coder
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CNibble4Coder::CNibble4Coder()
: iMainArray(50),
iOverflowArray(10)
{
DecodeReset();
}
// -----------------------------------------------------------------------------
// CNibble4Coder::~CNibble4Coder
// Destructor.
// -----------------------------------------------------------------------------
//
CNibble4Coder::~CNibble4Coder()
{
iMainArray.Close();
iOverflowArray.Close();
}
// -----------------------------------------------------------------------------
// CNibble4Coder::DecodeReset
// Moves cursor to the beginning of the array.
// -----------------------------------------------------------------------------
//
void CNibble4Coder::DecodeReset()
{
iPosition = 0;
iSlot = 0;
iOverflowPos = 0;
}
// -----------------------------------------------------------------------------
// CNibble4Coder::NextL
// Returns a value in the array and moves cursor forwards.
// -----------------------------------------------------------------------------
//
TUint32 CNibble4Coder::NextL()
{
if ( iPosition >= iMainArray.Count() )
{
User::Leave( KErrOverflow );
}
TUint result = iMainArray[ iPosition ];
// In binary, the array entry is something like:
// hhhhhhhhhhhhhhhhrrrrllllllllllll (32 bits)
// r = result bits we're after
// h = higher bits
// l = lower bits
// Drop the lower bits
result = result >> (4 * iSlot );
// Drop the higher bits
result = result & 0xf;
// If the value didn't fit to 4 bits, get it from the overflow array.
if ( result >= KNibble4Limit )
{
if ( iOverflowPos >= iOverflowArray.Count() )
{
User::Leave( KErrOverflow );
}
result = iOverflowArray[ iOverflowPos ];
iOverflowPos++;
}
// Update iterator
iSlot++;
if ( iSlot == 8 )
{
iPosition++;
iSlot = 0;
}
return( result );
}
// -----------------------------------------------------------------------------
// CNibble4Coder::ExternalizeL
// Stores the object to the stream.
// -----------------------------------------------------------------------------
//
void CNibble4Coder::ExternalizeL( RWriteStream& aStream )
{
aStream.WriteInt32L( KBinaryNibble4ID );
Externalize32bitArrayL( aStream, iMainArray );
Externalize32bitArrayL( aStream, iOverflowArray );
}
// -----------------------------------------------------------------------------
// Implementation of CRLECoder starts from here.
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
// CRLECoder::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CRLECoder* CRLECoder::NewL( const RArray<TUint16>& aPlainArray )
{
CRLECoder* me = new (ELeave) CRLECoder;
CleanupStack::PushL( me );
me->DecodeReset();
if ( aPlainArray.Count() == 0 )
{
CleanupStack::Pop();
return( me );
}
TInt count = aPlainArray.Count();
if ( count > 0 )
{
CRLECoder::TValueAndCount valueCount;
valueCount.iValue = aPlainArray[ 0 ];
valueCount.iCount = 1;
for ( TInt k( 1 ); k < count; k++ )
{
if ( aPlainArray[ k ] == valueCount.iValue )
{
valueCount.iCount++;
}
else{
User::LeaveIfError( me->iRleArray.Append( valueCount ) );
valueCount.iCount = 1;
valueCount.iValue = aPlainArray[ k ];
}
}
User::LeaveIfError( me->iRleArray.Append( valueCount ) );
}
CleanupStack::Pop( me );
return me;
}
// -----------------------------------------------------------------------------
// CRLECoder::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CRLECoder* CRLECoder::NewL( RReadStream& aStream )
{
CRLECoder* me = new (ELeave) CRLECoder;
CleanupStack::PushL( me );
me->DecodeReset();
if ( aStream.ReadInt32L() != KBinaryRLEID )
{
User::Leave( KErrCorrupt );
}
TInt count = aStream.ReadInt32L();
TInt err = KErrNone;
TUint32 value;
CRLECoder::TValueAndCount* valuePtr = (CRLECoder::TValueAndCount*)&value;
for ( TInt k( 0 ); k < count; k++ )
{
value = aStream.ReadInt32L();
err |= me->iRleArray.Append( *valuePtr );
}
User::LeaveIfError( err );
CleanupStack::Pop( me );
return( me );
}
// -----------------------------------------------------------------------------
// CRLECoder::CRLECoder
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CRLECoder::CRLECoder()
: iRleArray(50)
{
DecodeReset();
}
// -----------------------------------------------------------------------------
// CRLECoder::~CRLECoder
// Destructor.
// -----------------------------------------------------------------------------
//
CRLECoder::~CRLECoder()
{
iRleArray.Close();
}
// -----------------------------------------------------------------------------
// CRLECoder::DecodeReset
// Moves cursor to the beginning of the array.
// -----------------------------------------------------------------------------
//
void CRLECoder::DecodeReset()
{
iPosition = 0;
iRepetition = 0;
}
// -----------------------------------------------------------------------------
// CRLECoder::NextL
// Returns a value in the array and moves cursor forwards.
// -----------------------------------------------------------------------------
//
TUint16 CRLECoder::NextL()
{
if ( iPosition >= iRleArray.Count() )
{
User::Leave( KErrOverflow );
}
TUint16 result = iRleArray[iPosition].iValue;
iRepetition++;
TUint16 maxRepetitions = iRleArray[iPosition].iCount;
if ( iRepetition >= maxRepetitions )
{
iPosition++;
iRepetition = 0;
}
return result;
}
// -----------------------------------------------------------------------------
// CRLECoder::ExternalizeL
// Stores the object to the stream.
// -----------------------------------------------------------------------------
//
void CRLECoder::ExternalizeL( RWriteStream& aStream )
{
aStream.WriteInt32L( KBinaryRLEID );
TInt count = iRleArray.Count();
aStream.WriteInt32L( count );
if ( count > 0 )
{
TValueAndCount* startPtr = &(iRleArray[0]);
aStream.WriteL( (TUint8*)startPtr, sizeof(TValueAndCount) * count );
}
}
// -----------------------------------------------------------------------------
// Implementation of CYesNoCoder starts from here.
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
// CYesNoCoder::DecodeReset
// Moves cursor to the beginning of the array.
// -----------------------------------------------------------------------------
//
void CYesNoCoder::DecodeReset()
{
iPosition = 0;
iMask = 0x00000001;
}
// -----------------------------------------------------------------------------
// CYesNoCoder::NextBit
// Moves the cursor forwards.
// -----------------------------------------------------------------------------
//
void CYesNoCoder::NextBit(void)
{
// Increase the iterator.
iMask <<= 1;
if ( iMask == 0 )
{
iPosition++;
iMask = 1;
}
}
// -----------------------------------------------------------------------------
// CYesNoCoder::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CYesNoCoder* CYesNoCoder::NewL()
{
CYesNoCoder* me = new (ELeave) CYesNoCoder;
me->DecodeReset();
return( me );
}
// -----------------------------------------------------------------------------
// CYesNoCoder::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CYesNoCoder* CYesNoCoder::NewL( RReadStream& aStream )
{
CYesNoCoder* me = new (ELeave) CYesNoCoder;
CleanupStack::PushL( me );
me->DecodeReset();
Internalize32bitArrayL( aStream, me->iStore );
CleanupStack::Pop( me );
return( me );
}
// -----------------------------------------------------------------------------
// CYesNoCoder::CYesNoCoder
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CYesNoCoder::CYesNoCoder()
: iStore(10)
{
DecodeReset();
}
// -----------------------------------------------------------------------------
// CYesNoCoder::~CYesNoCoder
// Destructor.
// -----------------------------------------------------------------------------
//
CYesNoCoder::~CYesNoCoder()
{
iStore.Close();
}
// -----------------------------------------------------------------------------
// CYesNoCoder::EncodeL
// Encodes a bit.
// -----------------------------------------------------------------------------
//
void CYesNoCoder::EncodeL( TBool aValue )
{
// Do we need to grow the size of the array?
if ( iMask == 1 )
{
User::LeaveIfError( iStore.Append( 0 ) );
}
// Store the value, if it is 'yes'.
if ( aValue )
{
iStore[ iPosition ] |= iMask;
}
// Increase the iterator
NextBit();
}
// -----------------------------------------------------------------------------
// CYesNoCoder::NextL
// Returns a value in the array and moves cursor forwards.
// -----------------------------------------------------------------------------
//
TBool CYesNoCoder::NextL()
{
TBool result = iStore[ iPosition ] & iMask;
// Increase the iterator
NextBit();
return( result );
}
// -----------------------------------------------------------------------------
// CYesNoCoder::ExternalizeL
// Stores the object to the stream.
// (other items were commented in the headers)
// -----------------------------------------------------------------------------
//
void CYesNoCoder::ExternalizeL( RWriteStream& aStream )
{
aStream.WriteInt32L( KBinaryYesNoID );
Externalize32bitArrayL( aStream, iStore );
}
// End of File