diff -r 000000000000 -r 2e3d3ce01487 tzservices/tzserver/Server/Source/readonlytzdb.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tzservices/tzserver/Server/Source/readonlytzdb.cpp Tue Feb 02 10:12:00 2010 +0200 @@ -0,0 +1,516 @@ +// Copyright (c) 2004-2009 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: +// + +#include +#include "ReadOnlyTzDb.h" +#include +#include "dataprovider.h" +#include + +const TUint KDefaultTzNumericId = 0; + +// TZ Database is stored in the timezone server's own private area +_LIT(KTzDbFileNameRom,"Z:\\private\\1020383E\\TZDB.DBZ"); +_LIT(KTzDbFileNameFlash,"C:\\private\\1020383E\\TZDB.DBZ"); +_LIT(KTzDbFileNameFlashCorrupt,"C:\\private\\1020383E\\TZDB.DB~"); + +CReadOnlyTzDb* CReadOnlyTzDb::NewL(RFs& aFs, CTzSwiObserver& aSwiObserver, MTzDataObserver& aTzDataObserver) + { + CReadOnlyTzDb* self = new(ELeave) CReadOnlyTzDb(aFs, aSwiObserver, aTzDataObserver); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CReadOnlyTzDb::CReadOnlyTzDb(RFs& aFs, CTzSwiObserver& aSwiObserver, MTzDataObserver& aTzDataObserver) + : iFs(aFs), iSwiObserver(aSwiObserver), iTzDataObserver(aTzDataObserver), iTzDbDataFromFlash(EFalse) + { + } + +void CReadOnlyTzDb::ConstructL() + { + // Open the database, map the file into memory and build the entity tables + InitialiseL(); + // Add observer to watch SWI completion + iSwiObserver.AddObserverL(this); + } + +// +// Returns the memory address of the start of RAM copy of TZ Database file +// +TInt CReadOnlyTzDb::StartAddress() const + { + return iStartAddress; + } + +// +// Loads the TZ Database from given file into RAM. +// +TInt CReadOnlyTzDb::CopyDatabaseToRam(const TDesC& aTzDbFileName) + { + TInt error = KErrNone; + RFile file; + + TUint fileMode = EFileShareReadersOnly | EFileRead | EFileStream; + + error = file.Open(iFs, aTzDbFileName, fileMode); + if (error == KErrNone) + { + TInt size = 0; + error = file.Size(size); + if ( (error == KErrNone) && (size <= 0) ) + { + error = KErrCorrupt; + } + if (error == KErrNone) + { + if (iTzDbData) + { + iChunk.Close(); + iTzDbData = NULL; + } + + error = iChunk.CreateLocal(size,size) ; + if (error == KErrNone ) + { + // Allocate memory inside the memory chunk + iTzDbData = new (iChunk.Base()) TUint8 [size]; + // Set a TPtr to "point" at the created memory + TPtr8 flashDataPtr(iTzDbData, size); + + error = file.Read(0,flashDataPtr,size); + if (error == KErrNone) + { + iStartAddress = reinterpret_cast(iTzDbData); + } + } + } + } + file.Close(); + return error; + } + +TInt CReadOnlyTzDb::InvalidateFlashDatabaseL() + { + RFile file; + CleanupClosePushL(file); + TUint fileMode = EFileShareExclusive | EFileWrite | EFileStream; + TInt error = file.Open(iFs, KTzDbFileNameFlash, fileMode); + if (error == KErrNone) + { + error = file.Rename(KTzDbFileNameFlashCorrupt); + } + CleanupStack::PopAndDestroy(&file); + + return error; + } + +void CReadOnlyTzDb::InitialiseL() + { + // deny access to Flash-based database + // if it is being restored in this precise moment + // We must not allow access to the ROM-based DB either, + // because this might contain outdated data. + if (iRestoreInProcess) + { + User::Leave(KErrNotReady); + } + + // + // try to copy TZ Database from file in Flash drive + // + TInt error = CopyDatabaseToRam(KTzDbFileNameFlash); + + // + // if it wasn't found or couldn't be opened, try to copy from file in ROM + // + + if (error != KErrNone) + { + User::LeaveIfError(CopyDatabaseToRam(KTzDbFileNameRom)); + iTzDbDataFromFlash = false; + } + else + { + iTzDbDataFromFlash = true; + } + + // + // read header and initialise table offsets + // + + TTzHeader* header(reinterpret_cast(iStartAddress) ); + + // check that the db version is the expected + if (header->iVersion != KTzDbVersion) + { + if (iTzDbData) + { + ReleaseData(); + if (iTzDbDataFromFlash) + { + InvalidateFlashDatabaseL(); + } + } + User::Leave(KErrCorrupt); + } + + const TInt KStringsBaseAddress = iStartAddress + header->iOffsetToStringTable; + const TInt KRegionsBaseAddress = iStartAddress + header->iOffsetToRegionsTable; + const TInt KRegionalZonesBaseAddress = iStartAddress + header->iOffsetToRegionalZonesTable; + const TInt KZonesDataBaseAddress = iStartAddress + header->iOffsetToZones; + const TInt KZonesBaseAddress = iStartAddress + header->iOffsetToZonesTable; + const TInt KLinksBaseAddress = iStartAddress + header->iOffsetToLinksTable; + const TInt KStdTimeAlignmentsBaseAddress = iStartAddress + header->iOffsetToStdTimeAlignmentsTable; + const TInt KRuleSetsBaseAddress = iStartAddress + header->iOffsetToRuleSetsTable; + const TInt KRuleUsesBaseAddress = iStartAddress + header->iOffsetToRuleUsesTable; + const TInt KRuleDefinitionsBaseAddress = iStartAddress + header->iOffsetToRuleDefinitionsTable; + + // + // create tables + // + iStringsTable = CTzDbStringsTable::NewL(*(reinterpret_cast(KStringsBaseAddress))); + iRegionsTable = CTzDbRegionsTable::NewL(*this, *(reinterpret_cast(KRegionsBaseAddress))); + iRegionalZonesTable = CTzDbRegionalZonesTable::NewL(*this, *(reinterpret_cast(KRegionalZonesBaseAddress))); + iZonesTable = CTzDbZonesTable::NewL(*this, *(reinterpret_cast(KZonesBaseAddress)), KZonesDataBaseAddress); + iLinksTable = CTzDbLinksTable::NewL(*this, *(reinterpret_cast(KLinksBaseAddress))); + iStdTimeAlignmentsTable = CTzDbStdTimeAlignmentsTable::NewL(*(reinterpret_cast(KStdTimeAlignmentsBaseAddress))); + iRuleSetsTable = CTzDbRuleSetsTable::NewL(*this, *(reinterpret_cast(KRuleSetsBaseAddress))); + iRuleUsesTable = CTzDbRuleUsesTable::NewL(*(reinterpret_cast(KRuleUsesBaseAddress))); + iRuleDefinitionsTable = CTzDbRuleDefinitionsTable::NewL(*(reinterpret_cast(KRuleDefinitionsBaseAddress))); + } + +// +// Releases all RAM used by the database +// +void CReadOnlyTzDb::ReleaseData() + { + // delete all entity tables that are created at startup + delete iStringsTable; iStringsTable = NULL; + delete iRegionsTable; iRegionsTable = NULL; + delete iRegionalZonesTable; iRegionalZonesTable = NULL; + delete iZonesTable; iZonesTable = NULL; + delete iLinksTable; iLinksTable = NULL; + delete iStdTimeAlignmentsTable; iStdTimeAlignmentsTable = NULL; + delete iRuleSetsTable; iRuleSetsTable = NULL; + delete iRuleUsesTable; iRuleUsesTable = NULL; + delete iRuleDefinitionsTable; iRuleDefinitionsTable = NULL; + + iStartAddress = 0; + iChunk.Close(); iTzDbData = NULL; + } + +CReadOnlyTzDb::~CReadOnlyTzDb() + { + iSwiObserver.RemoveObserver(this); + ReleaseData(); + } + +// +// Returns the CTzId object that corresponds to the location set as default in the database +// +CTzId* CReadOnlyTzDb::GetDefaultTimeZoneIdL() + { + if (iZonesTable == NULL) + { + InitialiseL(); + } + + CTzId* defTZID = NULL; + CTzDbZone* defZone = GetZoneL((reinterpret_cast(iStartAddress))->iOffsetToDefaultZone); + + if (defZone) + { + CleanupStack::PushL(defZone); // push #1 + + HBufC8* fullZoneName = defZone->GetFullZoneNameLC(); // push #2 + defTZID = CTzId::NewL(defZone->LocationId()); + CleanupStack::PushL(defTZID); // push #3 + defTZID->SetIdL(*fullZoneName); + + CleanupStack::Pop(defTZID); + CleanupStack::PopAndDestroy(2, defZone); + } + + return defTZID; + } + +void CReadOnlyTzDb::GetTzRulesL(CTzRules& aTzRules, CTzId& aTzId) + { + if (iZonesTable == NULL) + { + InitialiseL(); + } + + TRAPD(err, DoGetTzRulesL(aTzRules, aTzId)); + if ( (err == KErrCorrupt) && (iTzDbData) ) + { + ReleaseData(); + // if the corruption occurred while accessing the Flash DB, we must flag it + // as corrupt before propagating the leave + if (iTzDbDataFromFlash) + { + InvalidateFlashDatabaseL(); + } + } + + User::LeaveIfError(err); + } + +void CReadOnlyTzDb::DoGetTzRulesL(CTzRules& aTzRules, CTzId& aTzId) + { + CTzDbZone* zone = FindZoneL(aTzId,ETrue); + if (zone) + { + CleanupStack::PushL(zone); + zone->GetRulesL(aTzRules); + CleanupStack::PopAndDestroy(zone); + } + } + +TBool CReadOnlyTzDb::IsIdInDbL(TUint aTzId) + { + if (iZonesTable == NULL) + { + InitialiseL(); + } + CTzDbZone* zone = FindZoneByNumericIdL(aTzId); + TBool ret = (zone)?ETrue:EFalse; + delete zone; + return ret; + } + +// +// Returns the CTzDbZone object corresponding to the location received (as CTzId) +// The supplied CTzId has two different IDs: a numeric one and a name (string ID). +// If the numeric ID is set (>0), it is used to perform the database search. Otherwise, +// the name is used to do the search. +// +// If aFillInLocationIDs is ETrue, it also fills in the unset zone ID in the supplied CTzId +// +CTzDbZone* CReadOnlyTzDb::FindZoneL(CTzId& aLocation, TBool aFillInLocationIDs) + { + CTzDbZone* zone = NULL; + if (aLocation.TimeZoneNumericID() > KDefaultTzNumericId) + { + zone = FindZoneByNumericIdL(aLocation.TimeZoneNumericID()); + if (zone && aFillInLocationIDs) + { + CleanupStack::PushL(zone); // push #1 + HBufC8* fullZoneName = zone->GetFullZoneNameLC(); // push #2 + aLocation.SetIdL(*fullZoneName); + CleanupStack::PopAndDestroy(fullZoneName); // pop #2 + CleanupStack::Pop(zone); // pop #1 + } + } + else + { + zone = FindZoneByNameL(aLocation.TimeZoneNameID()); + if (zone) + { + CleanupStack::PushL(zone); // push #1 + aLocation.SetId(zone->LocationId()); + CleanupStack::Pop(zone); // pop #1 + } + } + + return zone; + } + +// +// +// Looks for a Zone database entity given a location name +// Returns the Zone as a CTzDbZone* (NULL if it can't find +// a Zone in the database that matches the received location) +// +CTzDbZone* CReadOnlyTzDb::FindZoneByNameL(const TDesC8& aLocation) + { + // first of all, look in links table + CTzDbZone* retZone = iLinksTable->FindZoneL(aLocation); + + if (retZone == NULL) + { // received location was the name of an actual zone + // break up Location in Region and City names: e.g. "Europe/London" = "Europe" + "London" + TInt separatorOffset = aLocation.Locate('/'); + HBufC8* regionName; + HBufC8* cityName; + if (separatorOffset >= 0) + { + regionName = aLocation.Left(separatorOffset).AllocLC(); // push #1 + cityName = aLocation.Right(aLocation.Length() - (separatorOffset+1)).AllocLC(); // push #2 + } + else + { + _LIT8(KNullStr,""); + regionName = KNullStr().AllocLC(); // push #1 + cityName = aLocation.AllocLC(); // push #2 + } + CTzDbRegion* region = iRegionsTable->FindRegionL(*regionName); + if (region) + { + CleanupStack::PushL(region); // push #3 + retZone = region->FindZoneL(*cityName); + CleanupStack::PopAndDestroy(region); // pop #3 + } // if (region) + + CleanupStack::PopAndDestroy(2,regionName); // pop #2, #1 - cityName, regionName + } + + return retZone; + } + +CTzDbZone* CReadOnlyTzDb::FindZoneByNumericIdL(TUint aLocationId) + { + return iZonesTable->GetZoneByIdL(aLocationId); + } + +// +// +// The following methods provide access to the entity tables +// + +TPtrC8 CReadOnlyTzDb::GetStringL(TUint aOffset) const + { + return iStringsTable->GetStringL(aOffset); + } + +const TTzRuleDefinition& CReadOnlyTzDb::GetTRuleDefinition(TUint aOffset) const + { + return iRuleDefinitionsTable->GetRuleDefinition(aOffset); + } + +const TTzRegionalZoneIndex& CReadOnlyTzDb::GetTRegionalZoneIndex(TUint aReference) const + { + return iRegionalZonesTable->GetTRegionalZoneIndex(aReference); + } + +CTzDbZone* CReadOnlyTzDb::GetZoneL(TUint aReference) const + { + return iZonesTable->GetZoneL(aReference); + } + +const TTzZone& CReadOnlyTzDb::GetTZone(TUint aReference) const + { + return iZonesTable->GetTZone(aReference); + } + +const TTzStdTimeAlignment& CReadOnlyTzDb::GetTStdTimeAlignment(TUint aReference) const + { + return iStdTimeAlignmentsTable->GetTStdTimeAlignment(aReference); + } + +const TTzRuleUse& CReadOnlyTzDb::GetTRuleUse(TUint aReference) const + { + return iRuleUsesTable->GetTRuleUse(aReference); + } + +CTzDbRuleSet* CReadOnlyTzDb::GetRuleSetL(TUint aReference) const + { + return iRuleSetsTable->GetRuleSetL(aReference); + } + +// +// The following methods (inherited from MBackupRestoreNotificationObserver) +// provide BackupRestore support + +void CReadOnlyTzDb::BackupBeginningL() + { + // No action needed + } + +void CReadOnlyTzDb::BackupCompletedL() + { + // No action needed + } + +void CReadOnlyTzDb::RestoreBeginningL() + { + // set flag indicating that restoring has begun + SetRestoreInProcess(); + } + +void CReadOnlyTzDb::RestoreCompletedL() + { + // reset flag + ResetRestoreInProcess(); + ReleaseData(); + InitialiseL(); + } + +void CReadOnlyTzDb::HandleDatabaseChangeL(RTz::TTzChanges aChange) + { + //notify the TZ Data Observer that a change has occurred + iTzDataObserver.NotifyTZDataStatusChangeL(aChange); + + ReleaseData(); + InitialiseL(); + } + +/* +Retrieves the UTC offset for a given numeric time zone id. + +@param aTime time at which the UTC offset for given time zone is required. +@param aTzId a numeric time zone id, + +@return TInt offset from UTC (in minutes). +*/ +TInt CReadOnlyTzDb::GetOffsetForTimeZoneIdL(const TTime& aTime, TInt aTzId) + { + if (iZonesTable == NULL) + { + InitialiseL(); + } + + TInt offset = 0; + TDateTime nowDate(aTime.DateTime() ); + + CTzDbZone* zone = FindZoneByNumericIdL(aTzId);; + CTzDbStdTimeAlignment* timeAlignment; + + if (zone != NULL) + { + // + // zone has been found + // + CleanupStack::PushL(zone); + timeAlignment = zone->FindStdTimeAlignmentL + ( + nowDate.Year(), + nowDate.Month(), + nowDate.Day(), + nowDate.Hour(), + nowDate.Minute(), + ETzUtcTimeReference + ); + + if(timeAlignment) + { + offset = timeAlignment->UtcOffset(); + delete timeAlignment; + } + CleanupStack::PopAndDestroy(zone); + } + + return offset; + } + +// +// Called by CTzDbChangeNotifier to notify of a TZ Database change +// +void CReadOnlyTzDb::NotifyTZDataStatusChangeL(RTz::TTzChanges aChange) + { + HandleDatabaseChangeL(aChange); + }