|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <tz.h> |
|
17 #include "ReadOnlyTzDb.h" |
|
18 #include <f32file.h> |
|
19 #include "dataprovider.h" |
|
20 #include <vtzrules.h> |
|
21 |
|
22 const TUint KDefaultTzNumericId = 0; |
|
23 |
|
24 // TZ Database is stored in the timezone server's own private area |
|
25 _LIT(KTzDbFileNameRom,"Z:\\private\\1020383E\\TZDB.DBZ"); |
|
26 _LIT(KTzDbFileNameFlash,"C:\\private\\1020383E\\TZDB.DBZ"); |
|
27 _LIT(KTzDbFileNameFlashCorrupt,"C:\\private\\1020383E\\TZDB.DB~"); |
|
28 |
|
29 CReadOnlyTzDb* CReadOnlyTzDb::NewL(RFs& aFs, CTzSwiObserver& aSwiObserver, MTzDataObserver& aTzDataObserver) |
|
30 { |
|
31 CReadOnlyTzDb* self = new(ELeave) CReadOnlyTzDb(aFs, aSwiObserver, aTzDataObserver); |
|
32 CleanupStack::PushL(self); |
|
33 self->ConstructL(); |
|
34 CleanupStack::Pop(self); |
|
35 return self; |
|
36 } |
|
37 |
|
38 CReadOnlyTzDb::CReadOnlyTzDb(RFs& aFs, CTzSwiObserver& aSwiObserver, MTzDataObserver& aTzDataObserver) |
|
39 : iFs(aFs), iSwiObserver(aSwiObserver), iTzDataObserver(aTzDataObserver), iTzDbDataFromFlash(EFalse) |
|
40 { |
|
41 } |
|
42 |
|
43 void CReadOnlyTzDb::ConstructL() |
|
44 { |
|
45 // Open the database, map the file into memory and build the entity tables |
|
46 InitialiseL(); |
|
47 // Add observer to watch SWI completion |
|
48 iSwiObserver.AddObserverL(this); |
|
49 } |
|
50 |
|
51 // |
|
52 // Returns the memory address of the start of RAM copy of TZ Database file |
|
53 // |
|
54 TInt CReadOnlyTzDb::StartAddress() const |
|
55 { |
|
56 return iStartAddress; |
|
57 } |
|
58 |
|
59 // |
|
60 // Loads the TZ Database from given file into RAM. |
|
61 // |
|
62 TInt CReadOnlyTzDb::CopyDatabaseToRam(const TDesC& aTzDbFileName) |
|
63 { |
|
64 TInt error = KErrNone; |
|
65 RFile file; |
|
66 |
|
67 TUint fileMode = EFileShareReadersOnly | EFileRead | EFileStream; |
|
68 |
|
69 error = file.Open(iFs, aTzDbFileName, fileMode); |
|
70 if (error == KErrNone) |
|
71 { |
|
72 TInt size = 0; |
|
73 error = file.Size(size); |
|
74 if ( (error == KErrNone) && (size <= 0) ) |
|
75 { |
|
76 error = KErrCorrupt; |
|
77 } |
|
78 if (error == KErrNone) |
|
79 { |
|
80 if (iTzDbData) |
|
81 { |
|
82 iChunk.Close(); |
|
83 iTzDbData = NULL; |
|
84 } |
|
85 |
|
86 error = iChunk.CreateLocal(size,size) ; |
|
87 if (error == KErrNone ) |
|
88 { |
|
89 // Allocate memory inside the memory chunk |
|
90 iTzDbData = new (iChunk.Base()) TUint8 [size]; |
|
91 // Set a TPtr to "point" at the created memory |
|
92 TPtr8 flashDataPtr(iTzDbData, size); |
|
93 |
|
94 error = file.Read(0,flashDataPtr,size); |
|
95 if (error == KErrNone) |
|
96 { |
|
97 iStartAddress = reinterpret_cast<TInt>(iTzDbData); |
|
98 } |
|
99 } |
|
100 } |
|
101 } |
|
102 file.Close(); |
|
103 return error; |
|
104 } |
|
105 |
|
106 TInt CReadOnlyTzDb::InvalidateFlashDatabaseL() |
|
107 { |
|
108 RFile file; |
|
109 CleanupClosePushL(file); |
|
110 TUint fileMode = EFileShareExclusive | EFileWrite | EFileStream; |
|
111 TInt error = file.Open(iFs, KTzDbFileNameFlash, fileMode); |
|
112 if (error == KErrNone) |
|
113 { |
|
114 error = file.Rename(KTzDbFileNameFlashCorrupt); |
|
115 } |
|
116 CleanupStack::PopAndDestroy(&file); |
|
117 |
|
118 return error; |
|
119 } |
|
120 |
|
121 void CReadOnlyTzDb::InitialiseL() |
|
122 { |
|
123 // deny access to Flash-based database |
|
124 // if it is being restored in this precise moment |
|
125 // We must not allow access to the ROM-based DB either, |
|
126 // because this might contain outdated data. |
|
127 if (iRestoreInProcess) |
|
128 { |
|
129 User::Leave(KErrNotReady); |
|
130 } |
|
131 |
|
132 // |
|
133 // try to copy TZ Database from file in Flash drive |
|
134 // |
|
135 TInt error = CopyDatabaseToRam(KTzDbFileNameFlash); |
|
136 |
|
137 // |
|
138 // if it wasn't found or couldn't be opened, try to copy from file in ROM |
|
139 // |
|
140 |
|
141 if (error != KErrNone) |
|
142 { |
|
143 User::LeaveIfError(CopyDatabaseToRam(KTzDbFileNameRom)); |
|
144 iTzDbDataFromFlash = false; |
|
145 } |
|
146 else |
|
147 { |
|
148 iTzDbDataFromFlash = true; |
|
149 } |
|
150 |
|
151 // |
|
152 // read header and initialise table offsets |
|
153 // |
|
154 |
|
155 TTzHeader* header(reinterpret_cast<TTzHeader*>(iStartAddress) ); |
|
156 |
|
157 // check that the db version is the expected |
|
158 if (header->iVersion != KTzDbVersion) |
|
159 { |
|
160 if (iTzDbData) |
|
161 { |
|
162 ReleaseData(); |
|
163 if (iTzDbDataFromFlash) |
|
164 { |
|
165 InvalidateFlashDatabaseL(); |
|
166 } |
|
167 } |
|
168 User::Leave(KErrCorrupt); |
|
169 } |
|
170 |
|
171 const TInt KStringsBaseAddress = iStartAddress + header->iOffsetToStringTable; |
|
172 const TInt KRegionsBaseAddress = iStartAddress + header->iOffsetToRegionsTable; |
|
173 const TInt KRegionalZonesBaseAddress = iStartAddress + header->iOffsetToRegionalZonesTable; |
|
174 const TInt KZonesDataBaseAddress = iStartAddress + header->iOffsetToZones; |
|
175 const TInt KZonesBaseAddress = iStartAddress + header->iOffsetToZonesTable; |
|
176 const TInt KLinksBaseAddress = iStartAddress + header->iOffsetToLinksTable; |
|
177 const TInt KStdTimeAlignmentsBaseAddress = iStartAddress + header->iOffsetToStdTimeAlignmentsTable; |
|
178 const TInt KRuleSetsBaseAddress = iStartAddress + header->iOffsetToRuleSetsTable; |
|
179 const TInt KRuleUsesBaseAddress = iStartAddress + header->iOffsetToRuleUsesTable; |
|
180 const TInt KRuleDefinitionsBaseAddress = iStartAddress + header->iOffsetToRuleDefinitionsTable; |
|
181 |
|
182 // |
|
183 // create tables |
|
184 // |
|
185 iStringsTable = CTzDbStringsTable::NewL(*(reinterpret_cast<TTzStringsTable*>(KStringsBaseAddress))); |
|
186 iRegionsTable = CTzDbRegionsTable::NewL(*this, *(reinterpret_cast<TTzRegionsTable*>(KRegionsBaseAddress))); |
|
187 iRegionalZonesTable = CTzDbRegionalZonesTable::NewL(*this, *(reinterpret_cast<TTzRegionalZonesTable*>(KRegionalZonesBaseAddress))); |
|
188 iZonesTable = CTzDbZonesTable::NewL(*this, *(reinterpret_cast<TTzZonesTable*>(KZonesBaseAddress)), KZonesDataBaseAddress); |
|
189 iLinksTable = CTzDbLinksTable::NewL(*this, *(reinterpret_cast<TTzLinksTable*>(KLinksBaseAddress))); |
|
190 iStdTimeAlignmentsTable = CTzDbStdTimeAlignmentsTable::NewL(*(reinterpret_cast<TTzStdTimeAlignmentsTable*>(KStdTimeAlignmentsBaseAddress))); |
|
191 iRuleSetsTable = CTzDbRuleSetsTable::NewL(*this, *(reinterpret_cast<TTzRuleSetsTable*>(KRuleSetsBaseAddress))); |
|
192 iRuleUsesTable = CTzDbRuleUsesTable::NewL(*(reinterpret_cast<TTzRuleUsesTable*>(KRuleUsesBaseAddress))); |
|
193 iRuleDefinitionsTable = CTzDbRuleDefinitionsTable::NewL(*(reinterpret_cast<TTzRuleDefinitionsTable*>(KRuleDefinitionsBaseAddress))); |
|
194 } |
|
195 |
|
196 // |
|
197 // Releases all RAM used by the database |
|
198 // |
|
199 void CReadOnlyTzDb::ReleaseData() |
|
200 { |
|
201 // delete all entity tables that are created at startup |
|
202 delete iStringsTable; iStringsTable = NULL; |
|
203 delete iRegionsTable; iRegionsTable = NULL; |
|
204 delete iRegionalZonesTable; iRegionalZonesTable = NULL; |
|
205 delete iZonesTable; iZonesTable = NULL; |
|
206 delete iLinksTable; iLinksTable = NULL; |
|
207 delete iStdTimeAlignmentsTable; iStdTimeAlignmentsTable = NULL; |
|
208 delete iRuleSetsTable; iRuleSetsTable = NULL; |
|
209 delete iRuleUsesTable; iRuleUsesTable = NULL; |
|
210 delete iRuleDefinitionsTable; iRuleDefinitionsTable = NULL; |
|
211 |
|
212 iStartAddress = 0; |
|
213 iChunk.Close(); iTzDbData = NULL; |
|
214 } |
|
215 |
|
216 CReadOnlyTzDb::~CReadOnlyTzDb() |
|
217 { |
|
218 iSwiObserver.RemoveObserver(this); |
|
219 ReleaseData(); |
|
220 } |
|
221 |
|
222 // |
|
223 // Returns the CTzId object that corresponds to the location set as default in the database |
|
224 // |
|
225 CTzId* CReadOnlyTzDb::GetDefaultTimeZoneIdL() |
|
226 { |
|
227 if (iZonesTable == NULL) |
|
228 { |
|
229 InitialiseL(); |
|
230 } |
|
231 |
|
232 CTzId* defTZID = NULL; |
|
233 CTzDbZone* defZone = GetZoneL((reinterpret_cast<TTzHeader*>(iStartAddress))->iOffsetToDefaultZone); |
|
234 |
|
235 if (defZone) |
|
236 { |
|
237 CleanupStack::PushL(defZone); // push #1 |
|
238 |
|
239 HBufC8* fullZoneName = defZone->GetFullZoneNameLC(); // push #2 |
|
240 defTZID = CTzId::NewL(defZone->LocationId()); |
|
241 CleanupStack::PushL(defTZID); // push #3 |
|
242 defTZID->SetIdL(*fullZoneName); |
|
243 |
|
244 CleanupStack::Pop(defTZID); |
|
245 CleanupStack::PopAndDestroy(2, defZone); |
|
246 } |
|
247 |
|
248 return defTZID; |
|
249 } |
|
250 |
|
251 void CReadOnlyTzDb::GetTzRulesL(CTzRules& aTzRules, CTzId& aTzId) |
|
252 { |
|
253 if (iZonesTable == NULL) |
|
254 { |
|
255 InitialiseL(); |
|
256 } |
|
257 |
|
258 TRAPD(err, DoGetTzRulesL(aTzRules, aTzId)); |
|
259 if ( (err == KErrCorrupt) && (iTzDbData) ) |
|
260 { |
|
261 ReleaseData(); |
|
262 // if the corruption occurred while accessing the Flash DB, we must flag it |
|
263 // as corrupt before propagating the leave |
|
264 if (iTzDbDataFromFlash) |
|
265 { |
|
266 InvalidateFlashDatabaseL(); |
|
267 } |
|
268 } |
|
269 |
|
270 User::LeaveIfError(err); |
|
271 } |
|
272 |
|
273 void CReadOnlyTzDb::DoGetTzRulesL(CTzRules& aTzRules, CTzId& aTzId) |
|
274 { |
|
275 CTzDbZone* zone = FindZoneL(aTzId,ETrue); |
|
276 if (zone) |
|
277 { |
|
278 CleanupStack::PushL(zone); |
|
279 zone->GetRulesL(aTzRules); |
|
280 CleanupStack::PopAndDestroy(zone); |
|
281 } |
|
282 } |
|
283 |
|
284 TBool CReadOnlyTzDb::IsIdInDbL(TUint aTzId) |
|
285 { |
|
286 if (iZonesTable == NULL) |
|
287 { |
|
288 InitialiseL(); |
|
289 } |
|
290 CTzDbZone* zone = FindZoneByNumericIdL(aTzId); |
|
291 TBool ret = (zone)?ETrue:EFalse; |
|
292 delete zone; |
|
293 return ret; |
|
294 } |
|
295 |
|
296 // |
|
297 // Returns the CTzDbZone object corresponding to the location received (as CTzId) |
|
298 // The supplied CTzId has two different IDs: a numeric one and a name (string ID). |
|
299 // If the numeric ID is set (>0), it is used to perform the database search. Otherwise, |
|
300 // the name is used to do the search. |
|
301 // |
|
302 // If aFillInLocationIDs is ETrue, it also fills in the unset zone ID in the supplied CTzId |
|
303 // |
|
304 CTzDbZone* CReadOnlyTzDb::FindZoneL(CTzId& aLocation, TBool aFillInLocationIDs) |
|
305 { |
|
306 CTzDbZone* zone = NULL; |
|
307 if (aLocation.TimeZoneNumericID() > KDefaultTzNumericId) |
|
308 { |
|
309 zone = FindZoneByNumericIdL(aLocation.TimeZoneNumericID()); |
|
310 if (zone && aFillInLocationIDs) |
|
311 { |
|
312 CleanupStack::PushL(zone); // push #1 |
|
313 HBufC8* fullZoneName = zone->GetFullZoneNameLC(); // push #2 |
|
314 aLocation.SetIdL(*fullZoneName); |
|
315 CleanupStack::PopAndDestroy(fullZoneName); // pop #2 |
|
316 CleanupStack::Pop(zone); // pop #1 |
|
317 } |
|
318 } |
|
319 else |
|
320 { |
|
321 zone = FindZoneByNameL(aLocation.TimeZoneNameID()); |
|
322 if (zone) |
|
323 { |
|
324 CleanupStack::PushL(zone); // push #1 |
|
325 aLocation.SetId(zone->LocationId()); |
|
326 CleanupStack::Pop(zone); // pop #1 |
|
327 } |
|
328 } |
|
329 |
|
330 return zone; |
|
331 } |
|
332 |
|
333 // |
|
334 // |
|
335 // Looks for a Zone database entity given a location name |
|
336 // Returns the Zone as a CTzDbZone* (NULL if it can't find |
|
337 // a Zone in the database that matches the received location) |
|
338 // |
|
339 CTzDbZone* CReadOnlyTzDb::FindZoneByNameL(const TDesC8& aLocation) |
|
340 { |
|
341 // first of all, look in links table |
|
342 CTzDbZone* retZone = iLinksTable->FindZoneL(aLocation); |
|
343 |
|
344 if (retZone == NULL) |
|
345 { // received location was the name of an actual zone |
|
346 // break up Location in Region and City names: e.g. "Europe/London" = "Europe" + "London" |
|
347 TInt separatorOffset = aLocation.Locate('/'); |
|
348 HBufC8* regionName; |
|
349 HBufC8* cityName; |
|
350 if (separatorOffset >= 0) |
|
351 { |
|
352 regionName = aLocation.Left(separatorOffset).AllocLC(); // push #1 |
|
353 cityName = aLocation.Right(aLocation.Length() - (separatorOffset+1)).AllocLC(); // push #2 |
|
354 } |
|
355 else |
|
356 { |
|
357 _LIT8(KNullStr,""); |
|
358 regionName = KNullStr().AllocLC(); // push #1 |
|
359 cityName = aLocation.AllocLC(); // push #2 |
|
360 } |
|
361 CTzDbRegion* region = iRegionsTable->FindRegionL(*regionName); |
|
362 if (region) |
|
363 { |
|
364 CleanupStack::PushL(region); // push #3 |
|
365 retZone = region->FindZoneL(*cityName); |
|
366 CleanupStack::PopAndDestroy(region); // pop #3 |
|
367 } // if (region) |
|
368 |
|
369 CleanupStack::PopAndDestroy(2,regionName); // pop #2, #1 - cityName, regionName |
|
370 } |
|
371 |
|
372 return retZone; |
|
373 } |
|
374 |
|
375 CTzDbZone* CReadOnlyTzDb::FindZoneByNumericIdL(TUint aLocationId) |
|
376 { |
|
377 return iZonesTable->GetZoneByIdL(aLocationId); |
|
378 } |
|
379 |
|
380 // |
|
381 // |
|
382 // The following methods provide access to the entity tables |
|
383 // |
|
384 |
|
385 TPtrC8 CReadOnlyTzDb::GetStringL(TUint aOffset) const |
|
386 { |
|
387 return iStringsTable->GetStringL(aOffset); |
|
388 } |
|
389 |
|
390 const TTzRuleDefinition& CReadOnlyTzDb::GetTRuleDefinition(TUint aOffset) const |
|
391 { |
|
392 return iRuleDefinitionsTable->GetRuleDefinition(aOffset); |
|
393 } |
|
394 |
|
395 const TTzRegionalZoneIndex& CReadOnlyTzDb::GetTRegionalZoneIndex(TUint aReference) const |
|
396 { |
|
397 return iRegionalZonesTable->GetTRegionalZoneIndex(aReference); |
|
398 } |
|
399 |
|
400 CTzDbZone* CReadOnlyTzDb::GetZoneL(TUint aReference) const |
|
401 { |
|
402 return iZonesTable->GetZoneL(aReference); |
|
403 } |
|
404 |
|
405 const TTzZone& CReadOnlyTzDb::GetTZone(TUint aReference) const |
|
406 { |
|
407 return iZonesTable->GetTZone(aReference); |
|
408 } |
|
409 |
|
410 const TTzStdTimeAlignment& CReadOnlyTzDb::GetTStdTimeAlignment(TUint aReference) const |
|
411 { |
|
412 return iStdTimeAlignmentsTable->GetTStdTimeAlignment(aReference); |
|
413 } |
|
414 |
|
415 const TTzRuleUse& CReadOnlyTzDb::GetTRuleUse(TUint aReference) const |
|
416 { |
|
417 return iRuleUsesTable->GetTRuleUse(aReference); |
|
418 } |
|
419 |
|
420 CTzDbRuleSet* CReadOnlyTzDb::GetRuleSetL(TUint aReference) const |
|
421 { |
|
422 return iRuleSetsTable->GetRuleSetL(aReference); |
|
423 } |
|
424 |
|
425 // |
|
426 // The following methods (inherited from MBackupRestoreNotificationObserver) |
|
427 // provide BackupRestore support |
|
428 |
|
429 void CReadOnlyTzDb::BackupBeginningL() |
|
430 { |
|
431 // No action needed |
|
432 } |
|
433 |
|
434 void CReadOnlyTzDb::BackupCompletedL() |
|
435 { |
|
436 // No action needed |
|
437 } |
|
438 |
|
439 void CReadOnlyTzDb::RestoreBeginningL() |
|
440 { |
|
441 // set flag indicating that restoring has begun |
|
442 SetRestoreInProcess(); |
|
443 } |
|
444 |
|
445 void CReadOnlyTzDb::RestoreCompletedL() |
|
446 { |
|
447 // reset flag |
|
448 ResetRestoreInProcess(); |
|
449 ReleaseData(); |
|
450 InitialiseL(); |
|
451 } |
|
452 |
|
453 void CReadOnlyTzDb::HandleDatabaseChangeL(RTz::TTzChanges aChange) |
|
454 { |
|
455 //notify the TZ Data Observer that a change has occurred |
|
456 iTzDataObserver.NotifyTZDataStatusChangeL(aChange); |
|
457 |
|
458 ReleaseData(); |
|
459 InitialiseL(); |
|
460 } |
|
461 |
|
462 /* |
|
463 Retrieves the UTC offset for a given numeric time zone id. |
|
464 |
|
465 @param aTime time at which the UTC offset for given time zone is required. |
|
466 @param aTzId a numeric time zone id, |
|
467 |
|
468 @return TInt offset from UTC (in minutes). |
|
469 */ |
|
470 TInt CReadOnlyTzDb::GetOffsetForTimeZoneIdL(const TTime& aTime, TInt aTzId) |
|
471 { |
|
472 if (iZonesTable == NULL) |
|
473 { |
|
474 InitialiseL(); |
|
475 } |
|
476 |
|
477 TInt offset = 0; |
|
478 TDateTime nowDate(aTime.DateTime() ); |
|
479 |
|
480 CTzDbZone* zone = FindZoneByNumericIdL(aTzId);; |
|
481 CTzDbStdTimeAlignment* timeAlignment; |
|
482 |
|
483 if (zone != NULL) |
|
484 { |
|
485 // |
|
486 // zone has been found |
|
487 // |
|
488 CleanupStack::PushL(zone); |
|
489 timeAlignment = zone->FindStdTimeAlignmentL |
|
490 ( |
|
491 nowDate.Year(), |
|
492 nowDate.Month(), |
|
493 nowDate.Day(), |
|
494 nowDate.Hour(), |
|
495 nowDate.Minute(), |
|
496 ETzUtcTimeReference |
|
497 ); |
|
498 |
|
499 if(timeAlignment) |
|
500 { |
|
501 offset = timeAlignment->UtcOffset(); |
|
502 delete timeAlignment; |
|
503 } |
|
504 CleanupStack::PopAndDestroy(zone); |
|
505 } |
|
506 |
|
507 return offset; |
|
508 } |
|
509 |
|
510 // |
|
511 // Called by CTzDbChangeNotifier to notify of a TZ Database change |
|
512 // |
|
513 void CReadOnlyTzDb::NotifyTZDataStatusChangeL(RTz::TTzChanges aChange) |
|
514 { |
|
515 HandleDatabaseChangeL(aChange); |
|
516 } |