43 |
43 |
44 const TInt KVerRevSisVersionOlder = 200; |
44 const TInt KVerRevSisVersionOlder = 200; |
45 const TInt KVerRevSisVersionSame = 300; |
45 const TInt KVerRevSisVersionSame = 300; |
46 const TInt KVerRevSisVersionNewer = 400; |
46 const TInt KVerRevSisVersionNewer = 400; |
47 |
47 |
48 using namespace Swi; |
48 namespace Swi |
49 //namespace Swi |
|
50 // { |
|
51 // ----------------------------------------------------------------------- |
|
52 // Two-phased constructor |
|
53 // ----------------------------------------------------------------------- |
|
54 // |
|
55 CVersionRevisor* CVersionRevisor::NewL( CProgramStatus& aMainStatus ) |
|
56 { |
49 { |
57 CVersionRevisor* self = NewLC( aMainStatus ); |
50 // ----------------------------------------------------------------------- |
58 CleanupStack::Pop( self ); |
51 // Two-phased constructor |
59 return self; |
52 // ----------------------------------------------------------------------- |
60 } |
53 // |
61 |
54 CVersionRevisor* CVersionRevisor::NewL( CProgramStatus& aMainStatus ) |
62 // ------------------------------------------------------------------------ |
55 { |
63 // Two-phased constructor |
56 CVersionRevisor* self = NewLC( aMainStatus ); |
64 // ------------------------------------------------------------------------ |
57 CleanupStack::Pop( self ); |
65 // |
58 return self; |
66 CVersionRevisor* CVersionRevisor::NewLC( CProgramStatus& aMainStatus ) |
59 } |
67 { |
60 |
68 CVersionRevisor* self = new (ELeave) CVersionRevisor; |
61 // ------------------------------------------------------------------------ |
69 CleanupStack::PushL( self ); |
62 // Two-phased constructor |
70 self->ConstructL( aMainStatus ); |
63 // ------------------------------------------------------------------------ |
71 return self; |
64 // |
72 } |
65 CVersionRevisor* CVersionRevisor::NewLC( CProgramStatus& aMainStatus ) |
73 |
66 { |
74 // ----------------------------------------------------------------------- |
67 CVersionRevisor* self = new (ELeave) CVersionRevisor; |
75 // 2nd constructor |
68 CleanupStack::PushL( self ); |
76 // ----------------------------------------------------------------------- |
69 self->ConstructL( aMainStatus ); |
77 // |
70 return self; |
78 void CVersionRevisor::ConstructL( CProgramStatus& aMainStatus ) |
71 } |
79 { |
72 |
80 FLOG( _L("[VersionRev] ConstructL start") ); |
73 // ----------------------------------------------------------------------- |
81 iSisUninstaller = NULL; |
74 // 2nd constructor |
82 iStartupReason = KErrNone; |
75 // ----------------------------------------------------------------------- |
83 // Note revisor do not own this instance. |
76 // |
84 iProgramStatus = &aMainStatus; |
77 void CVersionRevisor::ConstructL( CProgramStatus& aMainStatus ) |
85 User::LeaveIfError( iFs.Connect() ); |
78 { |
86 // Get system startup reason. |
79 FLOG( _L("[VersionRev] ConstructL start") ); |
87 TRAP_IGNORE( StartUpReasonL() ); |
80 iSisUninstaller = NULL; |
88 FLOG( _L("[VersionRev] ConstructL end") ); |
81 iStartupReason = KErrNone; |
89 } |
82 // Note revisor do not own this instance. |
90 |
83 iProgramStatus = &aMainStatus; |
91 // ----------------------------------------------------------------------- |
84 User::LeaveIfError( iFs.Connect() ); |
92 // c++ destructor |
85 // Get system startup reason. |
93 // ----------------------------------------------------------------------- |
86 TRAP_IGNORE( StartUpReasonL() ); |
94 // |
87 FLOG( _L("[VersionRev] ConstructL end") ); |
95 CVersionRevisor::~CVersionRevisor() |
88 } |
96 { |
89 |
97 FLOG( _L("[VersionRev] ~CVersionRevisor start") ); |
90 // ----------------------------------------------------------------------- |
98 delete iSisUninstaller; |
91 // c++ destructor |
99 iSisUninstaller = NULL; |
92 // ----------------------------------------------------------------------- |
100 iStubDataArray.ResetAndDestroy(); |
93 // |
101 iFs.Close(); |
94 CVersionRevisor::~CVersionRevisor() |
102 FLOG( _L("[VersionRev] ~CVersionRevisor end") ); |
95 { |
103 } |
96 FLOG( _L("[VersionRev] ~CVersionRevisor start") ); |
104 |
97 delete iSisUninstaller; |
105 // ----------------------------------------------------------------------- |
98 iSisUninstaller = NULL; |
106 // Starts uninstall process. |
99 iStubDataArray.ResetAndDestroy(); |
107 // ----------------------------------------------------------------------- |
100 iFs.Close(); |
108 // |
101 FLOG( _L("[VersionRev] ~CVersionRevisor end") ); |
109 TInt CVersionRevisor::StartProcessL() |
102 } |
110 { |
103 |
111 FLOG( _L("[VersionRev] StartProcessL start") ); |
104 // ----------------------------------------------------------------------- |
112 TInt err = KErrNone; |
105 // Starts uninstall process. |
113 |
106 // ----------------------------------------------------------------------- |
114 // If firmware update is done, start scan process. |
107 // |
115 if( iStartupReason == EFirmwareUpdate ) |
108 TInt CVersionRevisor::StartProcessL() |
116 { |
109 { |
117 iSisUninstaller = |
110 FLOG( _L("[VersionRev] StartProcessL start") ); |
118 CSisPkgUninstaller::NewL( *iProgramStatus, *this ); |
111 TInt err = KErrNone; |
|
112 |
|
113 //#ifdef _DEBUG |
|
114 //FLOG( _L("[VersionRev] FOR TESTING: STARTUP REASON = Firmwareupdate ! ! !") ); |
|
115 //iStartupReason = EFirmwareUpdate; |
|
116 //#endif |
|
117 |
|
118 // If firmware update is done, start scan process. |
|
119 if( iStartupReason == EFirmwareUpdate ) |
|
120 { |
|
121 iSisUninstaller = |
|
122 CSisPkgUninstaller::NewL( *iProgramStatus, *this ); |
|
123 |
|
124 TRAP( err, ProcessStubFilesL() ); |
|
125 FLOG_1( _L("[VersionRev] Process stub TRAP error = %d"), err ); |
|
126 |
|
127 TRAP( err, ProcessSisRegistryL() ); |
|
128 FLOG_1( _L("[VersionRev] Process sis TRAP error = %d"), err ); |
|
129 |
|
130 iSisUninstaller->StartUninstallL(); |
|
131 } |
|
132 else |
|
133 { |
|
134 FLOG( _L("[VersionRev] StartProcessL: No firmware update") ); |
|
135 // Ok, no need to start process. Leave so main will call delete. |
|
136 User::Leave( KErrAbort ); |
|
137 } |
|
138 |
|
139 FLOG( _L("[VersionRev] StartProcessL end") ); |
|
140 return KErrNone; |
|
141 } |
|
142 |
|
143 // ----------------------------------------------------------------------- |
|
144 // Reads stub sis files. |
|
145 // ----------------------------------------------------------------------- |
|
146 // |
|
147 TInt CVersionRevisor::ProcessStubFilesL() |
|
148 { |
|
149 FLOG( _L("[VersionRev] ProcessStubFilesL start") ); |
|
150 CDir* dir; |
|
151 |
|
152 TInt err = iFs.GetDir( |
|
153 KVerRevStubSISDir, |
|
154 KEntryAttNormal, |
|
155 ESortNone, |
|
156 dir ); |
|
157 |
|
158 if ( err == KErrNone ) |
|
159 { |
|
160 CleanupStack::PushL( dir ); |
|
161 |
|
162 TInt count = dir->Count(); |
|
163 FLOG_1( _L("[VersionRev] Stub count = %d"), count ); |
|
164 |
|
165 for ( TInt index = 0; index < count; index++ ) |
|
166 { |
|
167 FLOG_1( _L("[VersionRev] Stub index = %d"), index ); |
|
168 TFileName stubName; |
|
169 stubName.Append( KVerRevStubSISDir ); |
|
170 stubName.Append( (*dir)[index].iName ); |
|
171 FLOG_1( _L("[VersionRev] Stub name: %S\n "), |
|
172 &(*dir)[index].iName ); |
|
173 // Function needs to be trapped because SisController leavs |
|
174 // if some corrupted file is in dir etc. |
|
175 TRAP( err, AppendStubInfoL( stubName ) ); |
|
176 } |
|
177 CleanupStack::PopAndDestroy( dir ); |
|
178 } |
|
179 |
|
180 FLOG( _L("[VersionRev] ProcessStubFilesL end") ); |
|
181 return err; |
|
182 } |
|
183 |
|
184 // ----------------------------------------------------------------------- |
|
185 // Checks rom updates from sis registry and adds pkg UID to array for |
|
186 // uninstaller process. |
|
187 // |
|
188 // Pre contitons for uninstall is: |
|
189 // 1. sis version is older or same as rom STUB version. |
|
190 // 2. sis has files only in C drvie. |
|
191 // 3. if sis version is same as stub version, all binary files must be |
|
192 // present in rom (z:\sys\bin). |
|
193 // Rom STUB <- SA = uninstalled |
|
194 // Rom STUB <- SP = no uninstall, returned drive is Z (0x04) |
|
195 // Rom STUB <- PU = no uninstall, returned drive is Z+C (0x2000004) |
|
196 // Rom STUB <- SA <- SP = SA is uninstalled, SP is not (n-gage) |
|
197 // Rom STUB <- SA <- PU = uninstalled |
|
198 // Rom STUB <- SA + emped. sis = SA is uninstalled, empedded pkg is not. |
|
199 // ----------------------------------------------------------------------- |
|
200 // |
|
201 TInt CVersionRevisor::ProcessSisRegistryL() |
|
202 { |
|
203 FLOG( _L("[VersionRev] ProcessSisRegistryL start") ); |
|
204 TInt stubArrayCount = iStubDataArray.Count(); |
|
205 FLOG_1( _L("[VersionRev] Stub array count = %d"), stubArrayCount ); |
|
206 |
|
207 if ( stubArrayCount ) |
|
208 { |
|
209 Swi::RSisRegistrySession sisRegSession; |
|
210 User::LeaveIfError( sisRegSession.Connect() ); |
|
211 CleanupClosePushL( sisRegSession ); |
|
212 |
|
213 Swi::RSisRegistryEntry entry; |
|
214 TInt err = KErrNone; |
|
215 |
|
216 // Search correct sis pagace and open entry to it. |
|
217 for ( TInt stubIndex = 0; stubIndex < stubArrayCount; stubIndex++ ) |
|
218 { |
|
219 TUid stubUID = iStubDataArray[stubIndex]->pkgUID; |
|
220 FLOG_1( _L("[VersionRev] Stub UID: 0x%x \n "), stubUID.iUid ); |
|
221 |
|
222 TBool isInstalled = sisRegSession.IsInstalledL( stubUID ); |
|
223 |
|
224 if ( isInstalled ) |
|
225 { |
|
226 err = entry.Open( sisRegSession, stubUID ); |
|
227 |
|
228 if ( !err ) |
|
229 { |
|
230 CleanupClosePushL( entry ); |
|
231 |
|
232 TUint drives = entry.InstalledDrivesL(); |
|
233 FLOG_1( _L("[VersionRev] Installe drive: 0x%x \n "), |
|
234 drives ); |
|
235 |
|
236 if ( drives == KVerRevDriveC ) |
|
237 { |
|
238 FLOG( _L("[VersionRev] SIS is installed to C:") ); |
|
239 FLOG( _L("[VersionRev] Check SIS version") ); |
|
240 |
|
241 TVersion stubVersion( |
|
242 iStubDataArray[stubIndex]->major, |
|
243 iStubDataArray[stubIndex]->minor, |
|
244 iStubDataArray[stubIndex]->build ); |
|
245 |
|
246 // Check sis and stub version. |
|
247 TInt ver = CompareVersions( |
|
248 entry.VersionL(), |
|
249 stubVersion ); |
|
250 FLOG_1( _L("[VersionRev] CompareVer.= %d "), ver ); |
|
251 TBool removePkg = EFalse; |
|
252 |
|
253 if ( ver == KVerRevSisVersionSame ) |
|
254 { |
|
255 // If version is same check that all binary |
|
256 // files in rom is found. If files are missing |
|
257 // do not remove sis pkg. |
|
258 FLOG( _L("[VersionRev] Sis version same")); |
|
259 removePkg = AllRomBinariesFoundL( entry ); |
|
260 } |
|
261 if ( ver == KVerRevSisVersionOlder ) |
|
262 { |
|
263 FLOG( _L("[VersionRev] Sis version older")); |
|
264 removePkg = ETrue; |
|
265 } |
|
266 |
|
267 // Add uid to uninstall array if removePkg is true. |
|
268 if ( removePkg ) |
|
269 { |
|
270 iSisUninstaller->AddUidToListL( stubUID ); |
|
271 FLOG_1( _L("[VersionRev] Uninst. UID:0x%x"), |
|
272 stubUID.iUid ); |
|
273 } |
|
274 }//if |
|
275 CleanupStack::PopAndDestroy(); //entry |
|
276 }//if |
|
277 } //if |
|
278 } //for |
|
279 CleanupStack::PopAndDestroy(); //sisRegSession |
|
280 } //if |
119 |
281 |
120 TRAP( err, ProcessStubFilesL() ); |
282 return KErrNone; |
121 FLOG_1( _L("[VersionRev] Process stub TRAP error = %d"), err ); |
283 } |
122 |
284 |
123 TRAP( err, ProcessSisRegistryL() ); |
285 |
124 FLOG_1( _L("[VersionRev] Process sis TRAP error = %d"), err ); |
286 // ----------------------------------------------------------------------- |
125 |
287 // This function reads firmware string and checks if firmware update has |
126 iSisUninstaller->StartUninstallL(); |
288 // been done. This function does create file to private directory and |
127 } |
289 // saves current firmware version string to it. |
128 else |
290 // ----------------------------------------------------------------------- |
129 { |
291 // |
130 FLOG( _L("[VersionRev] StartProcessL: No firmware update") ); |
292 void CVersionRevisor::StartUpReasonL() |
131 // Ok, no need to start process. Leave so main will call delete. |
293 { |
132 User::Leave( KErrAbort ); |
294 FLOG( _L("[VersionRev] StartUpReasonL") ); |
133 } |
295 iStartupReason = KErrNotFound; |
134 |
296 HBufC* currentVersionString = HBufC::NewLC( KVerRevStrLength*2 ); |
135 FLOG( _L("[VersionRev] StartProcessL end") ); |
297 TPtr currentStringPtr = currentVersionString->Des(); |
136 return KErrNone; |
298 |
137 } |
299 // Get current firmware string from sysutil. |
138 |
300 // Firmware string is saved to Z:\\resource\\versions\\sw.txt |
139 // ----------------------------------------------------------------------- |
301 SysUtil::GetSWVersion( currentStringPtr ); |
140 // Reads stub sis files. |
302 FLOG_1( _L("[VersionRev] Firmware version = %S "), |
141 // ----------------------------------------------------------------------- |
303 ¤tStringPtr ); |
142 // |
304 TUint result; |
143 TInt CVersionRevisor::ProcessStubFilesL() |
305 // If private directory is not found create it. |
144 { |
306 TInt err = iFs.Att( KVerRevPrivatePath, result ); |
145 FLOG( _L("[VersionRev] ProcessStubFilesL start") ); |
307 |
146 CDir* dir; |
308 if ( ! err == KErrNone && result & KEntryAttDir ) |
147 |
309 { |
148 TInt err = iFs.GetDir( |
310 iFs.CreatePrivatePath( EDriveC ); |
149 KVerRevStubSISDir, |
311 FLOG( _L("[VersionRev] StartUpReasonL: Create private folder") ); |
150 KEntryAttNormal, |
312 } |
151 ESortNone, |
313 |
152 dir ); |
314 RFile file; |
153 |
315 TFindFile find( iFs ); |
154 if ( err == KErrNone ) |
316 // Check if version file is found in Daemon private director. |
155 { |
317 err = find.FindByPath( KVerRevVersionFile(), &KVerRevPrivatePath() ); |
156 CleanupStack::PushL( dir ); |
318 FLOG_1( _L("[VersionRev] StartUpReasonL: Find file = %d"), err ); |
157 |
319 |
158 TInt count = dir->Count(); |
320 if ( err ) |
159 FLOG_1( _L("[VersionRev] Stub count = %d"), count ); |
|
160 |
|
161 for ( TInt index = 0; index < count; index++ ) |
|
162 { |
321 { |
163 FLOG_1( _L("[VersionRev] Stub index = %d"), index ); |
322 // If file is not found this is first boot or user memory (C:) has |
164 TFileName stubName; |
323 // been formatted. No need to start version checking but let's save |
165 stubName.Append( KVerRevStubSISDir ); |
324 // the current firmware version to Daemon private folder. |
166 stubName.Append( (*dir)[index].iName ); |
325 err = file.Create( |
167 FLOG_1( _L("[VersionRev] Stub name: %S\n "), |
|
168 &(*dir)[index].iName ); |
|
169 // Function needs to be trapped because SisController leavs |
|
170 // if some corrupted file is in dir etc. |
|
171 TRAP( err, AppendStubInfoL( stubName ) ); |
|
172 } |
|
173 CleanupStack::PopAndDestroy( dir ); |
|
174 } |
|
175 |
|
176 FLOG( _L("[VersionRev] ProcessStubFilesL end") ); |
|
177 return err; |
|
178 } |
|
179 |
|
180 // ----------------------------------------------------------------------- |
|
181 // Checks rom updates from sis registry and adds pkg UID to array for |
|
182 // uninstaller process. |
|
183 // |
|
184 // Pre contitons for uninstall is: |
|
185 // 1. sis version is older or same as rom STUB version. |
|
186 // 2. sis has files only in C drvie. |
|
187 // 3. if sis version is same as stub version, all binary files must be |
|
188 // present in rom (z:\sys\bin). |
|
189 // Rom STUB <- SA = uninstalled |
|
190 // Rom STUB <- SP = no uninstall, returned drive is Z (0x04) |
|
191 // Rom STUB <- PU = no uninstall, returned drive is Z+C (0x2000004) |
|
192 // Rom STUB <- SA <- SP = SA is uninstalled, SP is not (n-gage) |
|
193 // Rom STUB <- SA <- PU = uninstalled |
|
194 // Rom STUB <- SA + emped. sis = SA is uninstalled, empedded pkg is not. |
|
195 // ----------------------------------------------------------------------- |
|
196 // |
|
197 TInt CVersionRevisor::ProcessSisRegistryL() |
|
198 { |
|
199 FLOG( _L("[VersionRev] ProcessSisRegistryL start") ); |
|
200 TInt stubArrayCount = iStubDataArray.Count(); |
|
201 FLOG_1( _L("[VersionRev] Stub array count = %d"), stubArrayCount ); |
|
202 |
|
203 if ( stubArrayCount ) |
|
204 { |
|
205 Swi::RSisRegistrySession sisRegSession; |
|
206 User::LeaveIfError( sisRegSession.Connect() ); |
|
207 CleanupClosePushL( sisRegSession ); |
|
208 |
|
209 Swi::RSisRegistryEntry entry; |
|
210 TInt err = KErrNone; |
|
211 |
|
212 // Search correct sis pagace and open entry to it. |
|
213 for ( TInt stubIndex = 0; stubIndex < stubArrayCount; stubIndex++ ) |
|
214 { |
|
215 TUid stubUID = iStubDataArray[stubIndex]->pkgUID; |
|
216 FLOG_1( _L("[VersionRev] Stub UID: 0x%x \n "), stubUID.iUid ); |
|
217 |
|
218 TBool isInstalled = sisRegSession.IsInstalledL( stubUID ); |
|
219 |
|
220 if ( isInstalled ) |
|
221 { |
|
222 err = entry.Open( sisRegSession, stubUID ); |
|
223 |
|
224 if ( !err ) |
|
225 { |
|
226 CleanupClosePushL( entry ); |
|
227 |
|
228 TUint drives = entry.InstalledDrivesL(); |
|
229 FLOG_1( _L("[VersionRev] Installe drive: 0x%x \n "), |
|
230 drives ); |
|
231 |
|
232 if ( drives == KVerRevDriveC ) |
|
233 { |
|
234 FLOG( _L("[VersionRev] SIS is installed to C:") ); |
|
235 FLOG( _L("[VersionRev] Check SIS version") ); |
|
236 |
|
237 TVersion stubVersion( |
|
238 iStubDataArray[stubIndex]->major, |
|
239 iStubDataArray[stubIndex]->minor, |
|
240 iStubDataArray[stubIndex]->build ); |
|
241 |
|
242 // Check sis and stub version. |
|
243 TInt ver = CompareVersions( |
|
244 entry.VersionL(), |
|
245 stubVersion ); |
|
246 FLOG_1( _L("[VersionRev] CompareVer.= %d "), ver ); |
|
247 TBool removePkg = EFalse; |
|
248 |
|
249 if ( ver == KVerRevSisVersionSame ) |
|
250 { |
|
251 // If version is same check that all binary |
|
252 // files in rom is found. If files are missing |
|
253 // do not remove sis pkg. |
|
254 FLOG( _L("[VersionRev] Sis version same")); |
|
255 removePkg = AllRomBinariesFoundL( entry ); |
|
256 } |
|
257 if ( ver == KVerRevSisVersionOlder ) |
|
258 { |
|
259 FLOG( _L("[VersionRev] Sis version older")); |
|
260 removePkg = ETrue; |
|
261 } |
|
262 |
|
263 // Add uid to uninstall array if removePkg is true. |
|
264 if ( removePkg ) |
|
265 { |
|
266 iSisUninstaller->AddUidToListL( stubUID ); |
|
267 FLOG_1( _L("[VersionRev] Uninst. UID:0x%x"), |
|
268 stubUID.iUid ); |
|
269 } |
|
270 }//if |
|
271 CleanupStack::PopAndDestroy(); //entry |
|
272 }//if |
|
273 } //if |
|
274 } //for |
|
275 CleanupStack::PopAndDestroy(); //sisRegSession |
|
276 } //if |
|
277 |
|
278 return KErrNone; |
|
279 } |
|
280 |
|
281 |
|
282 // ----------------------------------------------------------------------- |
|
283 // This function reads firmware string and checks if firmware update has |
|
284 // been done. This function does create file to private directory and |
|
285 // saves current firmware version string to it. |
|
286 // ----------------------------------------------------------------------- |
|
287 // |
|
288 void CVersionRevisor::StartUpReasonL() |
|
289 { |
|
290 FLOG( _L("[VersionRev] StartUpReasonL") ); |
|
291 iStartupReason = KErrNotFound; |
|
292 HBufC* currentVersionString = HBufC::NewLC( KVerRevStrLength*2 ); |
|
293 TPtr currentStringPtr = currentVersionString->Des(); |
|
294 |
|
295 // Get current firmware string from sysutil. |
|
296 // Firmware string is saved to Z:\\resource\\versions\\sw.txt |
|
297 SysUtil::GetSWVersion( currentStringPtr ); |
|
298 FLOG_1( _L("[VersionRev] Firmware version = %S "), |
|
299 ¤tStringPtr ); |
|
300 TUint result; |
|
301 // If private directory is not found create it. |
|
302 TInt err = iFs.Att( KVerRevPrivatePath, result ); |
|
303 |
|
304 if ( ! err == KErrNone && result & KEntryAttDir ) |
|
305 { |
|
306 iFs.CreatePrivatePath( EDriveC ); |
|
307 FLOG( _L("[VersionRev] StartUpReasonL: Create private folder") ); |
|
308 } |
|
309 |
|
310 RFile file; |
|
311 TFindFile find( iFs ); |
|
312 // Check if version file is found in Daemon private director. |
|
313 err = find.FindByPath( KVerRevVersionFile(), &KVerRevPrivatePath() ); |
|
314 FLOG_1( _L("[VersionRev] StartUpReasonL: Find file = %d"), err ); |
|
315 |
|
316 if ( err ) |
|
317 { |
|
318 // If file is not found this is first boot or user memory (C:) has |
|
319 // been formatted. No need to start version checking but let's save |
|
320 // the current firmware version to Daemon private folder. |
|
321 err = file.Create( |
|
322 iFs, |
|
323 KVerRevVersionFile, |
|
324 EFileWrite|EFileRead|EFileStreamText ); |
|
325 |
|
326 FLOG_1( _L("[VersionRev] file create err = %d"), err ); |
|
327 User::LeaveIfError( err ); |
|
328 |
|
329 // Write current firmware version strign to file. |
|
330 WriteFileText( file, currentStringPtr ); |
|
331 |
|
332 file.Flush(); |
|
333 file.Close(); |
|
334 } |
|
335 else |
|
336 { |
|
337 |
|
338 HBufC* previousVersionString = HBufC::NewLC( KVerRevStrLength*2 ); |
|
339 TPtr previousStringPtr = previousVersionString->Des(); |
|
340 |
|
341 // Open firmware version file from private directory. |
|
342 err = file.Open( |
|
343 iFs, |
|
344 KVerRevVersionFile, |
|
345 EFileWrite|EFileRead|EFileStreamText ); |
|
346 |
|
347 FLOG_1( _L("[VersionRev] file open err = %d"), err ); |
|
348 User::LeaveIfError( err ); |
|
349 |
|
350 // Read previous firmware string from the file. |
|
351 ReadFileText( file, previousStringPtr ); |
|
352 FLOG_1( _L("[VersionRev] Previous sw version: %S"), |
|
353 &previousStringPtr ); |
|
354 |
|
355 file.Close(); |
|
356 |
|
357 if ( previousStringPtr.Length() != 0 ) |
|
358 { |
|
359 // Compare firmware strings. |
|
360 err = previousVersionString->Compare( currentStringPtr ); |
|
361 FLOG_1( _L("[VersionRev] String compare = %d"), err ); |
|
362 |
|
363 if ( err == KErrNone ) |
|
364 { |
|
365 // Strings are identical, no firmware update. |
|
366 iStartupReason = KErrNone; |
|
367 FLOG( _L("[VersionRev] iStartupReason = KErrNone") ); |
|
368 } |
|
369 else |
|
370 { |
|
371 iStartupReason = EFirmwareUpdate; |
|
372 FLOG( _L("[VersionRev] iStartupReason = EFirmwareUpdate") ); |
|
373 file.Replace( |
|
374 iFs, |
326 iFs, |
375 KVerRevVersionFile, |
327 KVerRevVersionFile, |
376 EFileWrite|EFileStreamText ); |
328 EFileWrite|EFileRead|EFileStreamText ); |
377 // Ok we have firmware update. Let's write new firmware |
329 |
378 // string to file and start version checking. |
330 FLOG_1( _L("[VersionRev] file create err = %d"), err ); |
379 WriteFileText( file, currentStringPtr ); |
331 User::LeaveIfError( err ); |
380 file.Flush(); |
332 |
381 file.Close(); |
333 // Write current firmware version strign to file. |
382 } |
334 WriteFileText( file, currentStringPtr ); |
383 } |
335 |
384 CleanupStack::PopAndDestroy(); //previousVersionString |
336 file.Flush(); |
385 } |
337 file.Close(); |
386 CleanupStack::PopAndDestroy( ); //currentVersionString |
338 } |
387 } |
339 else |
388 |
340 { |
389 |
341 |
390 // ----------------------------------------------------------------------- |
342 HBufC* previousVersionString = HBufC::NewLC( KVerRevStrLength*2 ); |
391 // Help function to read firmware version string from file. |
343 TPtr previousStringPtr = previousVersionString->Des(); |
392 // ----------------------------------------------------------------------- |
344 |
393 // |
345 // Open firmware version file from private directory. |
394 void CVersionRevisor::ReadFileText( RFile& aFile, TDes& aText ) |
346 err = file.Open( |
395 { |
347 iFs, |
396 TFileText fileText; |
348 KVerRevVersionFile, |
397 fileText.Set( aFile ); |
349 EFileWrite|EFileRead|EFileStreamText ); |
398 fileText.Read( aText ); |
350 |
|
351 FLOG_1( _L("[VersionRev] file open err = %d"), err ); |
|
352 User::LeaveIfError( err ); |
|
353 |
|
354 // Read previous firmware string from the file. |
|
355 ReadFileText( file, previousStringPtr ); |
|
356 FLOG_1( _L("[VersionRev] Previous sw version: %S"), |
|
357 &previousStringPtr ); |
|
358 |
|
359 file.Close(); |
|
360 |
|
361 if ( previousStringPtr.Length() != 0 ) |
|
362 { |
|
363 // Compare firmware strings. |
|
364 err = previousVersionString->Compare( currentStringPtr ); |
|
365 FLOG_1( _L("[VersionRev] String compare = %d"), err ); |
|
366 |
|
367 if ( err == KErrNone ) |
|
368 { |
|
369 // Strings are identical, no firmware update. |
|
370 iStartupReason = KErrNone; |
|
371 FLOG( _L("[VersionRev] iStartupReason = KErrNone") ); |
|
372 } |
|
373 else |
|
374 { |
|
375 iStartupReason = EFirmwareUpdate; |
|
376 FLOG( _L("[VersionRev] iStartupReason = EFirmwareUpdate") ); |
|
377 file.Replace( |
|
378 iFs, |
|
379 KVerRevVersionFile, |
|
380 EFileWrite|EFileStreamText ); |
|
381 // Ok we have firmware update. Let's write new firmware |
|
382 // string to file and start version checking. |
|
383 WriteFileText( file, currentStringPtr ); |
|
384 file.Flush(); |
|
385 file.Close(); |
|
386 } |
|
387 } |
|
388 CleanupStack::PopAndDestroy(); //previousVersionString |
|
389 } |
|
390 CleanupStack::PopAndDestroy( ); //currentVersionString |
|
391 } |
399 |
392 |
400 // Replace new-line patterns with real ones. |
393 |
401 TInt position = aText.Find( KVerRevNewLinePattern ); |
394 // ----------------------------------------------------------------------- |
402 while ( position != KErrNotFound ) |
395 // Help function to read firmware version string from file. |
403 { |
396 // ----------------------------------------------------------------------- |
404 // err is a position |
397 // |
405 aText.Replace( |
398 void CVersionRevisor::ReadFileText( RFile& aFile, TDes& aText ) |
406 position, |
399 { |
407 KVerRevNewLinePattern().Length(), |
400 TFileText fileText; |
408 KVerRevNewLine ); |
401 fileText.Set( aFile ); |
|
402 fileText.Read( aText ); |
409 |
403 |
410 position = aText.Find( KVerRevNewLinePattern ); |
404 // Replace new-line patterns with real ones. |
411 } |
405 TInt position = aText.Find( KVerRevNewLinePattern ); |
412 } |
406 while ( position != KErrNotFound ) |
413 |
407 { |
414 |
408 // err is a position |
415 // ----------------------------------------------------------------------- |
409 aText.Replace( |
416 // Help function to write firmware version string from file. |
410 position, |
417 // ----------------------------------------------------------------------- |
411 KVerRevNewLinePattern().Length(), |
418 // |
412 KVerRevNewLine ); |
419 void CVersionRevisor::WriteFileText( RFile& aFile, TDes& aText ) |
413 |
420 { |
414 position = aText.Find( KVerRevNewLinePattern ); |
421 // Replace real new-line marker with pattern. This makes |
415 } |
422 // reading operation easy. |
416 } |
423 TInt position = aText.Find( KVerRevNewLine ); |
417 |
424 while ( position != KErrNotFound ) |
418 |
425 { |
419 // ----------------------------------------------------------------------- |
426 aText.Replace( |
420 // Help function to write firmware version string from file. |
427 position, |
421 // ----------------------------------------------------------------------- |
428 KVerRevNewLine().Length(), |
422 // |
429 KVerRevNewLinePattern ); |
423 void CVersionRevisor::WriteFileText( RFile& aFile, TDes& aText ) |
430 |
424 { |
431 position = aText.Find( KVerRevNewLine ); |
425 // Replace real new-line marker with pattern. This makes |
432 } |
426 // reading operation easy. |
433 |
427 TInt position = aText.Find( KVerRevNewLine ); |
434 TFileText fileText; |
428 while ( position != KErrNotFound ) |
435 fileText.Set( aFile ); |
429 { |
436 fileText.Write( aText ); |
430 aText.Replace( |
437 } |
431 position, |
438 |
432 KVerRevNewLine().Length(), |
439 |
433 KVerRevNewLinePattern ); |
440 // ----------------------------------------------------------------------- |
434 |
441 // This function reads stub sis files version and uid and adds the info |
435 position = aText.Find( KVerRevNewLine ); |
442 // in array. |
436 } |
443 // ----------------------------------------------------------------------- |
437 |
444 // |
438 TFileText fileText; |
445 void CVersionRevisor::AppendStubInfoL( TDesC& aStubName ) |
439 fileText.Set( aFile ); |
446 { |
440 fileText.Write( aText ); |
447 CFileSisDataProvider* provider = |
441 } |
448 CFileSisDataProvider::NewLC( iFs, aStubName ); |
442 |
449 |
443 |
450 Sis::CController* stubData = Sis::CController::NewLC( *provider ); |
444 // ----------------------------------------------------------------------- |
451 |
445 // This function reads stub sis files version and uid and adds the info |
452 const Sis::CVersion& version = stubData->Info().Version(); |
446 // in array. |
453 |
447 // ----------------------------------------------------------------------- |
454 TVersionRevStubData* stubPkg = new( ELeave ) TVersionRevStubData(); |
448 // |
455 CleanupStack::PushL( stubPkg ); |
449 void CVersionRevisor::AppendStubInfoL( TDesC& aStubName ) |
456 stubPkg->pkgUID = stubData->Info().Uid().Uid(); |
450 { |
457 stubPkg->major = version.Major(); |
451 CFileSisDataProvider* provider = |
458 stubPkg->minor = version.Minor(); |
452 CFileSisDataProvider::NewLC( iFs, aStubName ); |
459 stubPkg->build = version.Build(); |
453 |
460 |
454 Sis::CController* stubData = Sis::CController::NewLC( *provider ); |
461 iStubDataArray.AppendL( stubPkg ); |
455 |
462 |
456 const Sis::CVersion& version = stubData->Info().Version(); |
463 CleanupStack::Pop( stubPkg ); |
457 |
464 |
458 TVersionRevStubData* stubPkg = new( ELeave ) TVersionRevStubData(); |
465 #ifdef _DEBUG |
459 CleanupStack::PushL( stubPkg ); |
466 RDebug::Print( _L("[VersionRev] Add Stub UID: 0x%x Ver: %d.%d.%d\n "), |
460 stubPkg->pkgUID = stubData->Info().Uid().Uid(); |
467 stubData->Info().Uid().Uid(), |
461 stubPkg->major = version.Major(); |
468 version.Major(), |
462 stubPkg->minor = version.Minor(); |
469 version.Minor(), |
463 stubPkg->build = version.Build(); |
470 version.Build() ); |
464 |
471 #endif |
465 iStubDataArray.AppendL( stubPkg ); |
472 |
466 |
473 CleanupStack::PopAndDestroy( 2, provider ); |
467 CleanupStack::Pop( stubPkg ); |
474 provider = NULL; |
468 |
475 stubData = NULL; |
469 #ifdef _DEBUG |
476 stubPkg = NULL; |
470 RDebug::Print( _L("[VersionRev] Add Stub UID: 0x%x Ver: %d.%d.%d\n "), |
477 } |
471 stubData->Info().Uid().Uid(), |
478 |
472 version.Major(), |
479 // ----------------------------------------------------------------------- |
473 version.Minor(), |
480 // This function compares sis and stub versions. |
474 version.Build() ); |
481 // ----------------------------------------------------------------------- |
475 #endif |
482 // |
|
483 TInt CVersionRevisor::CompareVersions( |
|
484 TVersion aSisVer, |
|
485 TVersion aStubVer ) |
|
486 { |
|
487 FLOG( _L("[VersionRev] CompareVersions()") ); |
|
488 |
476 |
489 // Compare major version |
477 CleanupStack::PopAndDestroy( 2, provider ); |
490 if ( aSisVer.iMajor > aStubVer.iMajor ) |
478 provider = NULL; |
491 { |
479 stubData = NULL; |
492 FLOG( _L("[VersionRev] STUB major version older ") ); |
480 stubPkg = NULL; |
493 return KVerRevSisVersionNewer; |
481 } |
494 } |
482 |
495 // If same major version, check minor version. |
483 // ----------------------------------------------------------------------- |
496 else if ( aSisVer.iMajor == aStubVer.iMajor ) |
484 // This function compares sis and stub versions. |
497 { |
485 // ----------------------------------------------------------------------- |
498 if ( aSisVer.iMinor > aStubVer.iMinor ) |
486 // |
|
487 TInt CVersionRevisor::CompareVersions( |
|
488 TVersion aSisVer, |
|
489 TVersion aStubVer ) |
|
490 { |
|
491 FLOG( _L("[VersionRev] CompareVersions()") ); |
|
492 |
|
493 // Compare major version |
|
494 if ( aSisVer.iMajor > aStubVer.iMajor ) |
499 { |
495 { |
500 FLOG( _L("[VersionRev] STUB minor version older ") ); |
496 FLOG( _L("[VersionRev] STUB major version older ") ); |
501 return KVerRevSisVersionNewer; |
497 return KVerRevSisVersionNewer; |
502 } |
498 } |
503 // If same minor version, check build version. |
499 // If same major version, check minor version. |
504 else if ( aSisVer.iMinor == aStubVer.iMinor ) |
500 else if ( aSisVer.iMajor == aStubVer.iMajor ) |
|
501 { |
|
502 if ( aSisVer.iMinor > aStubVer.iMinor ) |
|
503 { |
|
504 FLOG( _L("[VersionRev] STUB minor version older ") ); |
|
505 return KVerRevSisVersionNewer; |
|
506 } |
|
507 // If same minor version, check build version. |
|
508 else if ( aSisVer.iMinor == aStubVer.iMinor ) |
|
509 { |
|
510 if ( aSisVer.iBuild > aStubVer.iBuild ) |
|
511 { |
|
512 FLOG( _L("[VersionRev] STUB build version older ") ); |
|
513 return KVerRevSisVersionNewer; |
|
514 } |
|
515 else if ( aSisVer.iBuild == aStubVer.iBuild ) |
|
516 { |
|
517 // Sis build version is same as stub. |
|
518 FLOG( _L("[VersionRev] Build version same ") ); |
|
519 return KVerRevSisVersionSame; |
|
520 } |
|
521 else // build |
|
522 { |
|
523 // Sis build version is older. |
|
524 FLOG( _L("[VersionRev] SIS build version OLDER !") ); |
|
525 return KVerRevSisVersionOlder; |
|
526 } |
|
527 } |
|
528 else // minor |
|
529 { |
|
530 // Sis minor version is older. |
|
531 FLOG( _L("[VersionRev] SIS minor version OLDER !") ); |
|
532 return KVerRevSisVersionOlder; |
|
533 } |
|
534 } |
|
535 else //major |
505 { |
536 { |
506 if ( aSisVer.iBuild > aStubVer.iBuild ) |
537 // Sis major version is older. |
507 { |
538 FLOG( _L("[VersionRev] SIS major version OLDER !") ); |
508 FLOG( _L("[VersionRev] STUB build version older ") ); |
|
509 return KVerRevSisVersionNewer; |
|
510 } |
|
511 else if ( aSisVer.iBuild == aStubVer.iBuild ) |
|
512 { |
|
513 // Sis build version is same as stub. |
|
514 FLOG( _L("[VersionRev] Build version same ") ); |
|
515 return KVerRevSisVersionSame; |
|
516 } |
|
517 else // build |
|
518 { |
|
519 // Sis build version is older. |
|
520 FLOG( _L("[VersionRev] SIS build version OLDER !") ); |
|
521 return KVerRevSisVersionOlder; |
|
522 } |
|
523 } |
|
524 else // minor |
|
525 { |
|
526 // Sis minor version is older. |
|
527 FLOG( _L("[VersionRev] SIS minor version OLDER !") ); |
|
528 return KVerRevSisVersionOlder; |
539 return KVerRevSisVersionOlder; |
529 } |
540 } |
530 } |
541 } |
531 else //major |
542 |
|
543 // ----------------------------------------------------------------------- |
|
544 // This function check that all sis pkg's binary files are found from rom. |
|
545 // ----------------------------------------------------------------------- |
|
546 // |
|
547 TBool CVersionRevisor::AllRomBinariesFoundL( Swi::RSisRegistryEntry& aEntry ) |
532 { |
548 { |
533 // Sis major version is older. |
549 FLOG( _L("[VersionRev] AllRomBinariesFoundL") ); |
534 FLOG( _L("[VersionRev] SIS major version OLDER !") ); |
550 TBool allBinaryFilesFound = EFalse; |
535 return KVerRevSisVersionOlder; |
551 TInt err = KErrNone; |
536 } |
552 RPointerArray<HBufC> sisFilesArray; |
537 } |
553 RPointerArray<HBufC> binaryFilesArray; |
538 |
554 |
539 // ----------------------------------------------------------------------- |
555 // Get installed files from this entry. |
540 // This function check that all sis pkg's binary files are found from rom. |
556 aEntry.FilesL( sisFilesArray ); |
541 // ----------------------------------------------------------------------- |
557 TInt arrayCount = sisFilesArray.Count(); |
542 // |
558 FLOG_1( _L("[VersionRev] Sis files count = %d"), arrayCount ); |
543 TBool CVersionRevisor::AllRomBinariesFoundL( Swi::RSisRegistryEntry& aEntry ) |
559 |
544 { |
560 if ( arrayCount ) |
545 FLOG( _L("[VersionRev] AllRomBinariesFoundL") ); |
561 { |
546 TBool allBinaryFilesFound = EFalse; |
562 for ( TInt index = 0; index < arrayCount; index++ ) |
547 TInt err = KErrNone; |
|
548 RPointerArray<HBufC> sisFilesArray; |
|
549 RPointerArray<HBufC> binaryFilesArray; |
|
550 |
|
551 // Get installed files from this entry. |
|
552 aEntry.FilesL( sisFilesArray ); |
|
553 TInt arrayCount = sisFilesArray.Count(); |
|
554 FLOG_1( _L("[VersionRev] Sis files count = %d"), arrayCount ); |
|
555 |
|
556 if ( arrayCount ) |
|
557 { |
|
558 for ( TInt index = 0; index < arrayCount; index++ ) |
|
559 { |
|
560 // Get file path |
|
561 HBufC* tempFilePath = sisFilesArray[index]->AllocL(); |
|
562 CleanupStack::PushL( tempFilePath ); |
|
563 FLOG_1( _L("[VersionRev] File path: %S \n"), tempFilePath ); |
|
564 |
|
565 // Check if file is installed to sys\bin folder. |
|
566 // Search \sys\bin string from the descriptor's data. |
|
567 err = tempFilePath->Find( KVerRevSysPath ); |
|
568 FLOG_1( _L("[VersionRev] Sys path found = %d"), err ); |
|
569 |
|
570 if ( err != KErrNotFound ) |
|
571 { |
563 { |
572 // If binary file, add to array. |
564 // Get file path |
573 binaryFilesArray.Append( tempFilePath ); |
565 HBufC* tempFilePath = sisFilesArray[index]->AllocL(); |
574 CleanupStack::Pop(); //tempFilePath |
566 CleanupStack::PushL( tempFilePath ); |
|
567 FLOG_1( _L("[VersionRev] File path: %S \n"), tempFilePath ); |
|
568 |
|
569 // Check if file is installed to sys\bin folder. |
|
570 // Search \sys\bin string from the descriptor's data. |
|
571 err = tempFilePath->Find( KVerRevSysPath ); |
|
572 FLOG_1( _L("[VersionRev] Sys path found = %d"), err ); |
|
573 |
|
574 if ( err != KErrNotFound ) |
|
575 { |
|
576 // If binary file, add to array. |
|
577 binaryFilesArray.Append( tempFilePath ); |
|
578 CleanupStack::Pop(); //tempFilePath |
|
579 } |
|
580 else |
|
581 { |
|
582 // Delete temp descriptor. |
|
583 CleanupStack::PopAndDestroy( tempFilePath ); |
|
584 tempFilePath = NULL; |
|
585 } |
575 } |
586 } |
576 else |
587 |
|
588 // Count how meny binary files are found. |
|
589 TInt binaryCount = binaryFilesArray.Count(); |
|
590 FLOG_1( _L("[VersionRev] Binary files count = %d"), binaryCount ); |
|
591 if ( binaryCount ) |
577 { |
592 { |
578 // Delete temp descriptor. |
593 TInt foundInRomCount = 0; |
579 CleanupStack::PopAndDestroy( tempFilePath ); |
594 TFindFile find( iFs ); |
580 tempFilePath = NULL; |
595 TParse stringParser; |
581 } |
596 TFileName binaryFileNameAndExt; |
|
597 |
|
598 for ( TInt index = 0; index < binaryCount; index++ ) |
|
599 { |
|
600 // Get binary file path. |
|
601 HBufC* binaryPathBuf = binaryFilesArray[index]; |
|
602 // Parse file name and extension. |
|
603 stringParser.Set( *binaryPathBuf ,NULL, NULL ); |
|
604 binaryFileNameAndExt.Copy( stringParser.NameAndExt() ); |
|
605 FLOG_1( _L("[VersionRev] Search file: %S \n"), |
|
606 &binaryFileNameAndExt ); |
|
607 |
|
608 // Search file in z:\sys\bin. |
|
609 // Note path must contain drive letter. |
|
610 err = find.FindByPath( |
|
611 binaryFileNameAndExt, |
|
612 &KVerRevRomSysPath() ); |
|
613 FLOG_1( _L("[VersionRev] Found in rom = %d"), err ); |
|
614 |
|
615 if ( err == KErrNone ) |
|
616 { |
|
617 // File found in rom. Increase counter. |
|
618 foundInRomCount++; |
|
619 } |
|
620 } //for |
|
621 |
|
622 // Check that all binary files are found in rom. |
|
623 if ( binaryCount == foundInRomCount ) |
|
624 { |
|
625 allBinaryFilesFound = ETrue; |
|
626 FLOG( _L("[VersionRev] All rom file found !") ); |
|
627 } |
|
628 } //if |
|
629 |
|
630 // Free all objects and array. |
|
631 binaryFilesArray.ResetAndDestroy(); |
582 } |
632 } |
583 |
|
584 // Count how meny binary files are found. |
|
585 TInt binaryCount = binaryFilesArray.Count(); |
|
586 FLOG_1( _L("[VersionRev] Binary files count = %d"), binaryCount ); |
|
587 if ( binaryCount ) |
|
588 { |
|
589 TInt foundInRomCount = 0; |
|
590 TFindFile find( iFs ); |
|
591 TParse stringParser; |
|
592 TFileName binaryFileNameAndExt; |
|
593 |
|
594 for ( TInt index = 0; index < binaryCount; index++ ) |
|
595 { |
|
596 // Get binary file path. |
|
597 HBufC* binaryPathBuf = binaryFilesArray[index]; |
|
598 // Parse file name and extension. |
|
599 stringParser.Set( *binaryPathBuf ,NULL, NULL ); |
|
600 binaryFileNameAndExt.Copy( stringParser.NameAndExt() ); |
|
601 FLOG_1( _L("[VersionRev] Search file: %S \n"), |
|
602 &binaryFileNameAndExt ); |
|
603 |
|
604 // Search file in z:\sys\bin. |
|
605 // Note path must contain drive letter. |
|
606 err = find.FindByPath( |
|
607 binaryFileNameAndExt, |
|
608 &KVerRevRomSysPath() ); |
|
609 FLOG_1( _L("[VersionRev] Found in rom = %d"), err ); |
|
610 |
|
611 if ( err == KErrNone ) |
|
612 { |
|
613 // File found in rom. Increase counter. |
|
614 foundInRomCount++; |
|
615 } |
|
616 } //for |
|
617 |
|
618 // Check that all binary files are found in rom. |
|
619 if ( binaryCount == foundInRomCount ) |
|
620 { |
|
621 allBinaryFilesFound = ETrue; |
|
622 FLOG( _L("[VersionRev] All rom file found !") ); |
|
623 } |
|
624 } //if |
|
625 |
|
626 // Free all objects and array. |
633 // Free all objects and array. |
627 binaryFilesArray.ResetAndDestroy(); |
634 sisFilesArray.ResetAndDestroy(); |
628 } |
635 |
629 // Free all objects and array. |
636 return allBinaryFilesFound; |
630 sisFilesArray.ResetAndDestroy(); |
637 } |
631 |
638 |
632 return allBinaryFilesFound; |
639 |
633 } |
640 // ----------------------------------------------------------------------- |
634 |
641 // This function handles VersionRevisors self exit. |
635 |
642 // ----------------------------------------------------------------------- |
636 // ----------------------------------------------------------------------- |
643 // |
637 // This function handles VersionRevisors self exit. |
644 void CVersionRevisor::Exit() |
638 // ----------------------------------------------------------------------- |
645 { |
639 // |
646 FLOG( _L("[VersionRev] Exit() ") ); |
640 void CVersionRevisor::Exit() |
647 // Ok all is done. Free all resources and exit. |
641 { |
648 delete this; |
642 FLOG( _L("[VersionRev] Exit() ") ); |
649 } |
643 // Ok all is done. Free all resources and exit. |
650 |
644 delete this; |
651 } // namespace Swi |
645 } |
|
646 |
|
647 // } // namespace Swi |
|
648 |
652 |
649 //EOF |
653 //EOF |