tzservices/tzserver/Server/Source/readonlytzdb.cpp
changeset 0 2e3d3ce01487
child 81 676b6116ca93
--- /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 <tz.h>
+#include "ReadOnlyTzDb.h"
+#include <f32file.h>
+#include "dataprovider.h"
+#include <vtzrules.h>
+
+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<TInt>(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<TTzHeader*>(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<TTzStringsTable*>(KStringsBaseAddress)));
+	iRegionsTable = CTzDbRegionsTable::NewL(*this, *(reinterpret_cast<TTzRegionsTable*>(KRegionsBaseAddress)));
+	iRegionalZonesTable = CTzDbRegionalZonesTable::NewL(*this, *(reinterpret_cast<TTzRegionalZonesTable*>(KRegionalZonesBaseAddress)));
+	iZonesTable = CTzDbZonesTable::NewL(*this, *(reinterpret_cast<TTzZonesTable*>(KZonesBaseAddress)), KZonesDataBaseAddress);
+	iLinksTable	= CTzDbLinksTable::NewL(*this, *(reinterpret_cast<TTzLinksTable*>(KLinksBaseAddress)));
+	iStdTimeAlignmentsTable	= CTzDbStdTimeAlignmentsTable::NewL(*(reinterpret_cast<TTzStdTimeAlignmentsTable*>(KStdTimeAlignmentsBaseAddress)));
+	iRuleSetsTable = CTzDbRuleSetsTable::NewL(*this, *(reinterpret_cast<TTzRuleSetsTable*>(KRuleSetsBaseAddress)));
+	iRuleUsesTable = CTzDbRuleUsesTable::NewL(*(reinterpret_cast<TTzRuleUsesTable*>(KRuleUsesBaseAddress)));
+	iRuleDefinitionsTable = CTzDbRuleDefinitionsTable::NewL(*(reinterpret_cast<TTzRuleDefinitionsTable*>(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<TTzHeader*>(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);
+	}