/*
* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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 represents the Widget Preferences object
*
*/
// INCLUDE FILES
#include <e32std.h>
#include <S32FILE.H>
#include <f32file.h>
#include <uri16.h>
#include <e32hashtab.h>
#include "Preferences.h"
// EXTERNAL DATA STRUCTURES
// EXTERNAL FUNCTION PROTOTYPES
// CONSTANTS
const TInt KMaxIntLength = 10;
const TInt KMaxKeyValueSize = 4096; //4 k
_LIT( KKeyFormat, "%d.%S" );
_LIT( KPrefsFile,"prefs.dat" );
// ----------------------------------------------------------------------------
// WidgetPreferences::WidgetPreferences
// C++ Constructor
//
//
// ----------------------------------------------------------------------------
WidgetPreferences::WidgetPreferences() :m_widgetid(0),
m_widgetbundleid(0),
m_basepath(0),
m_filepath(0)
{
m_preferences = new RPtrHashMap<TDesC,PrefElement>();
}
// ----------------------------------------------------------------------------
// WidgetPreferences::~WidgetPreferences
// Destructor
//
//
// ----------------------------------------------------------------------------
WidgetPreferences::~WidgetPreferences()
{
TRAP_IGNORE( saveL() );
if (m_preferences) {
m_preferences->ResetAndDestroy();
m_preferences->Close();
delete m_preferences;
}
delete m_basepath;
delete m_widgetbundleid;
delete m_filepath;
}
// ----------------------------------------------------------------------------
// WidgetPreferences::setBasePathL
//
//
// ----------------------------------------------------------------------------
void WidgetPreferences::setBasePathL(const TDesC& aValue)
{
m_basepath = aValue.AllocL();
}
// ----------------------------------------------------------------------------
// WidgetPreferences::setWidgetId
//
//
// ----------------------------------------------------------------------------
void WidgetPreferences::setWidgetId(TInt aValue)
{
m_widgetid = aValue;
}
// ----------------------------------------------------------------------------
// WidgetPreferences::setBundleIdL
//
//
// ----------------------------------------------------------------------------
void WidgetPreferences::setWidgetBundleId(const TDesC& aValue)
{
m_widgetbundleid = aValue.AllocL();
}
// ----------------------------------------------------------------------------
// WidgetPreferences::setBundleIdL
//
//
// ----------------------------------------------------------------------------
TDesC& WidgetPreferences::getWidgetBundleId()
{
return *m_widgetbundleid;
}
// ----------------------------------------------------------------------------
// WidgetPreferences::PreferenceL
// Get preference for a key
//
//
// ----------------------------------------------------------------------------
TInt WidgetPreferences::preferenceL( const TDesC& akey, TPtrC& avalue)
{
TInt rSuccess = KErrNotFound;
TInt size = 0;
if ( !m_basepath || (m_basepath->Length() <= 0) )
return rSuccess;
if ( akey.Length() <= KMaxKeyValueSize ) {
HBufC* k = HBufC::NewLC( akey.Length() + KMaxIntLength + 1 );
k->Des().Format( KKeyFormat, m_widgetid, &akey );
PrefElement* pref = m_preferences->Find( *k );
if ( !pref ) {
CleanupStack::PopAndDestroy( k );
return rSuccess;
}
size = pref->valueSize();
if ( size > KMaxKeyValueSize ) {
// return contents from temp file whose name is stored
// in the m_value member of m_preferences
RFs fs;
if ( fs.Connect() == KErrNone ) {
CleanupClosePushL( fs );
HBufC* filePath = HBufC::NewLC( pref->value().Length() );
TPtr fName( filePath->Des() );
fName.Append( pref->value() );
RFileReadStream readStream;
if ( readStream.Open( fs, *filePath, EFileRead ) == KErrNone ) {
CleanupClosePushL( readStream );
TInt len( readStream.ReadInt32L() );
if ( len > 0 ) {
HBufC* v = HBufC::NewLC( len );
TPtr ptrvalue = v->Des();
readStream.ReadL( ptrvalue, len );
avalue.Set( *v );
CleanupStack::Pop( v );
rSuccess = KErrNone;
}
CleanupStack::PopAndDestroy();//readStream
}
CleanupStack::PopAndDestroy( 2 ); //filePath,fs
}
}
else if ( size >= 0 ) {
avalue.Set( pref->value() );
rSuccess = KErrNone;
}
CleanupStack::PopAndDestroy( k );
}
return rSuccess;
}
// ----------------------------------------------------------------------------
// WidgetPreferences::SetPreferenceL
// set Preference for a key
//
//
// ----------------------------------------------------------------------------
void WidgetPreferences::setPreferenceL( const TDesC& akey, const TDesC& avalue)
{
if ( !m_basepath || (m_basepath->Length() <= 0) )
return;
if ( akey.Length() <= KMaxKeyValueSize ) {
HBufC* k = HBufC::NewLC( akey.Length() + KMaxIntLength + 1 );
k->Des().Format( KKeyFormat, m_widgetid, &akey );
// if hash has the key and its value
// delete the old value later when the new value was successfully updated
PrefElement* prefExisting = NULL;
prefExisting = m_preferences->Find( *k );
if ( avalue.Length() <= KMaxKeyValueSize ) {
PrefElement* pref = new (ELeave) PrefElement;
CleanupStack::PushL( pref );
pref->setValueL( avalue );
pref->setValueSize( avalue.Length() );
m_preferences->InsertL( k, pref );
CleanupStack::Pop(); //pref
}
else {
// create a temp file and save the value in temp file.
// m_value member of PrefElement contains the temp file name.
RFs fs;
RFile file;
if ( fs.Connect() == KErrNone ) {
CleanupClosePushL( fs );
// create and write to file
TFileName tempFileName;
file.Temp( fs, *m_basepath, tempFileName, EFileWrite|EFileShareExclusive );
CleanupClosePushL( file );
HBufC* filePath = HBufC::NewLC( tempFileName.Length() );
TPtr fName( filePath->Des() );
fName.Append( tempFileName );
RFileWriteStream writeStream( file );
CleanupClosePushL( writeStream );
TRAPD( err,
writeStream.WriteInt32L( avalue.Length() );
writeStream.WriteL( avalue );
writeStream.CommitL(); );
// If an error occured while writing to the file, delete the temp file
// This should be the case when disk is full
if ( err != KErrNone )
{
CleanupStack::PopAndDestroy( ); //writeStream
file.Close();
fs.Delete( *filePath );
User::Leave( err );
}
// create new preference element
PrefElement* pref = new ( ELeave ) PrefElement;
CleanupStack::PushL( pref );
pref->setValueSize( avalue.Length() );
pref->setValueL( *filePath );
// update new preference element
m_preferences->InsertL( k, pref );
CleanupStack::Pop( pref );
CleanupStack::PopAndDestroy( ); //writeStream
CleanupStack::PopAndDestroy( 3 ); //filePath,file,fs
}
}
// now the new value is updated, it's safe to delete the old value
if ( prefExisting ) {
prefExisting->setCleanFileFlag( ETrue );
delete prefExisting;
}
CleanupStack::Pop(); // k
}
}
// ----------------------------------------------------------------------------
// WidgetPreferences::removePreferenceL
// remove Preference for a key
//
//
// ----------------------------------------------------------------------------
void WidgetPreferences::removePreferenceL( const TDesC& akey, const TDesC& avalue)
{
if ( !m_basepath || (m_basepath->Length() <= 0) )
return;
// double check value is NULL
if ( avalue != KNullDesC ) {
return;
}
if ( akey.Length() <= KMaxKeyValueSize ) {
HBufC* k = HBufC::NewLC( akey.Length() + KMaxIntLength + 1 );
k->Des().Format( KKeyFormat, m_widgetid, &akey );
// if hash has the key and its value
// delete the old value later when the new value was successfully updated
PrefElement* prefExisting = NULL;
prefExisting = m_preferences->Find( *k );
m_preferences->Remove(k);
// now the new value is updated, it's safe to delete the old value
if ( prefExisting ) {
prefExisting->setCleanFileFlag( ETrue );
delete prefExisting;
}
CleanupStack::PopAndDestroy(); // k
}
}
// ----------------------------------------------------------------------------
// WidgetPreferences::SaveL
// SAve preferences to persistent storage
//
//
// ----------------------------------------------------------------------------
void WidgetPreferences::saveL()
{
if ( !m_basepath || (m_basepath->Length() <= 0) )
return;
RFs fs;
if ( fs.Connect() == KErrNone ) {
CleanupClosePushL( fs );
HBufC* filePath = HBufC::NewLC( m_basepath->Length() + KPrefsFile().Length() );
TPtr fName( filePath->Des() );
fName.Append( *m_basepath );
fName.Append( KPrefsFile );
RFileWriteStream writeStream;
TInt fileerror = writeStream.Replace( fs, *filePath, EFileWrite );
if ( fileerror != KErrNone ) {
fs.CreatePrivatePath( EDriveC );
fileerror = writeStream.Create( fs, *filePath, EFileWrite|EFileShareExclusive );
}
if ( fileerror == KErrNone ) {
CleanupClosePushL( writeStream );
writeStream.WriteInt32L( m_preferences->Count() );
TPtrHashMapIter<TDesC,PrefElement> it( *m_preferences );
const TDesC* key;
const PrefElement* pref;
while ( ( key = it.NextKey() ) != 0 ) {
pref = it.CurrentValue();
writeStream.WriteInt32L( key->Length() );
writeStream.WriteL( *key );
writeStream.WriteInt32L( pref->value().Length() );
writeStream.WriteL( pref->value() );
writeStream.WriteInt32L( pref->valueSize() );
}
writeStream.CommitL();
CleanupStack::PopAndDestroy(); //writeStream
}
CleanupStack::PopAndDestroy( 2 ); //fs,filePath
}
}
// ----------------------------------------------------------------------------
// WidgetPreferences::LoadL
// Load preferences from persistent storage
//
//
// ----------------------------------------------------------------------------
void WidgetPreferences::loadL()
{
RFs fs;
if ( !m_basepath || (m_basepath->Length() <= 0) )
return;
if ( fs.Connect() == KErrNone ) {
CleanupClosePushL( fs );
HBufC* filePath = HBufC::NewLC( m_basepath->Length() + KPrefsFile().Length() );
TPtr fName( filePath->Des() );
fName.Append( *m_basepath );
fName.Append( KPrefsFile );
RFileReadStream readStream;
if ( readStream.Open( fs, *filePath, EFileRead ) == KErrNone ) {
CleanupClosePushL( readStream );
TInt count( readStream.ReadInt32L() );
for( TInt i = 0; i < count; i++ ) {
TInt len = readStream.ReadInt32L();
if ( len > 0 ) {
HBufC* key = HBufC::NewLC( len );
TPtr ptrkey = key->Des();
readStream.ReadL( ptrkey, len );
len = readStream.ReadInt32L();
if ( len <= KMaxKeyValueSize ) {
HBufC* value = HBufC::NewLC( len );
TPtr ptrvalue = value->Des();
readStream.ReadL( ptrvalue, len );
PrefElement* pref = new ( ELeave ) PrefElement;
CleanupStack::PushL( pref );
pref->setValueL( ptrvalue );
TInt size = readStream.ReadInt32L();
pref->setValueSize( size );
m_preferences->InsertL( key, pref );
CleanupStack::Pop(); //pref
CleanupStack::PopAndDestroy(); //value
CleanupStack::Pop(); //key
}
else {
CleanupStack::PopAndDestroy( key );
}
}
else {
break;
}
}
CleanupStack::PopAndDestroy(); //readStream
}
CleanupStack::PopAndDestroy( 2 ); //fs,filePath
}
}
// ----------------------------------------------------------------------------
// PrefElement::PrefElement
// C++ constructor
//
//
// ----------------------------------------------------------------------------
PrefElement::PrefElement() : m_value (0), m_valuesize (0), m_cleanFileFlag (EFalse)
{
}
// ----------------------------------------------------------------------------
// PrefElement::~PrefElement
// Destructor
//
//
// ----------------------------------------------------------------------------
PrefElement::~PrefElement()
{
// When we update the existing key with newer value:
// if the value > 4k, which means a file was created to store the value;
// we need to delete the old file.
// If called from ~Preferences(), we shouldn't do this -- cleanFileFlag is false
if ( m_cleanFileFlag && m_valuesize > KMaxKeyValueSize ) {
HBufC* filePathExisting = HBufC::NewLC( value().Length() );
TPtr fName( filePathExisting->Des() );
fName.Append( value() );
RFs fs;
if ( fs.Connect() == KErrNone ) {
fs.Delete(*filePathExisting);
fs.Close();
}
CleanupStack::PopAndDestroy(); //filePathExisting
}
delete m_value;
}
// ----------------------------------------------------------------------------
// PrefElement::setValueL
// set value for a preference
//
//
// ----------------------------------------------------------------------------
void PrefElement::setValueL( const TDesC& value )
{
if ( m_value ) {
delete m_value;
}
m_value = value.AllocL();
}