|
1 // Copyright (c) 1997-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 "APSRECCACHE.h" |
|
17 #include "APSSES.H" |
|
18 |
|
19 // |
|
20 // Constants |
|
21 |
|
22 const TUint KMaxNumberOfEntries = 200; |
|
23 // |
|
24 |
|
25 CRecognitionResultHashMapEntry* CRecognitionResultHashMapEntry::NewL(const TDesC& aFileName, TTime aLastModified, const TDataRecognitionResult& aResult, CRecognitionResultHashMapEntry* aNext) |
|
26 { |
|
27 CRecognitionResult* result = CRecognitionResult::NewL(aFileName, aResult); |
|
28 CleanupClosePushL(*result); |
|
29 CRecognitionResultHashMapEntry* self = new(ELeave) CRecognitionResultHashMapEntry(aLastModified, result, aNext); |
|
30 CleanupStack::Pop(result); |
|
31 return self; |
|
32 } |
|
33 |
|
34 CRecognitionResultHashMapEntry::CRecognitionResultHashMapEntry(TTime aLastModified, CRecognitionResult* aResult, CRecognitionResultHashMapEntry* aNext) |
|
35 : iLastModified(aLastModified), iResult(aResult), iNext(aNext) |
|
36 { |
|
37 } |
|
38 |
|
39 CRecognitionResultHashMapEntry::~CRecognitionResultHashMapEntry() |
|
40 { |
|
41 iResult->Close(); |
|
42 iResult = NULL; |
|
43 delete iNext; |
|
44 } |
|
45 |
|
46 void CRecognitionResultHashMapEntry::UpdateL(TTime aLastModified, const TDataRecognitionResult& aResult) |
|
47 { |
|
48 // since other objects might have a pointer to the CRecognitionResult object |
|
49 // and rely on the value not changing we need to create a new object to take |
|
50 // its place. |
|
51 |
|
52 CRecognitionResult* result = CRecognitionResult::NewL(FileName(), aResult); |
|
53 iResult->Close(); |
|
54 iResult = result; |
|
55 |
|
56 iLastModified = aLastModified; |
|
57 } |
|
58 |
|
59 // |
|
60 // CRecognitionResultHashMap |
|
61 // |
|
62 |
|
63 CRecognitionResultHashMap::CRecognitionResultHashMap() |
|
64 { |
|
65 } |
|
66 |
|
67 CRecognitionResultHashMap::~CRecognitionResultHashMap() |
|
68 { |
|
69 for(TUint i = 0; i < KFileHashMapEntries; i++) |
|
70 { |
|
71 delete Entry(i); |
|
72 } |
|
73 } |
|
74 |
|
75 CRecognitionResult* CRecognitionResultHashMap::Get(const TDesC& aKey, TTime& aLastModified) const |
|
76 { |
|
77 const TUint index = GetIndex(aKey); |
|
78 |
|
79 for(const CRecognitionResultHashMapEntry* entry = Entry(index); entry; entry = entry->Next()) |
|
80 { |
|
81 if(entry->FileName().Compare(aKey) == 0) |
|
82 { |
|
83 aLastModified = entry->LastModified(); |
|
84 return entry->Result(); |
|
85 } |
|
86 } |
|
87 return NULL; |
|
88 } |
|
89 |
|
90 /** |
|
91 Adds a recognition result to the hash map of the particular directory. |
|
92 This is only done if it isn't already existing. |
|
93 The return value specifies if the number of entries was increased by one (ETrue) or not. |
|
94 @internalComponent |
|
95 */ |
|
96 TBool CRecognitionResultHashMap::AddL(const TDesC& aKey, TTime aLastModified, const TDataRecognitionResult& aResult) |
|
97 { |
|
98 const TUint index = GetIndex(aKey); |
|
99 |
|
100 //check if there already is an entry for the file |
|
101 for(CRecognitionResultHashMapEntry* entry = Entry(index); entry; entry = entry->Next()) |
|
102 { |
|
103 if(entry->FileName().Compare(aKey) == 0) |
|
104 { |
|
105 // already there -> check modification date |
|
106 if( entry->LastModified() != aLastModified ) |
|
107 { |
|
108 entry->UpdateL(aLastModified, aResult); |
|
109 } |
|
110 |
|
111 return EFalse; |
|
112 } |
|
113 } |
|
114 |
|
115 //create new entry |
|
116 SetEntry(index, CRecognitionResultHashMapEntry::NewL(aKey, aLastModified, aResult, Entry(index))); |
|
117 iNumberOfEntries++; |
|
118 return ETrue; |
|
119 } |
|
120 |
|
121 TUint CRecognitionResultHashMap::GetIndex(const TDesC& aKey) const |
|
122 { |
|
123 // That's the hash algorithm |
|
124 TUint hash = aKey.Length(); |
|
125 for(TUint i=0;i< aKey.Length();i++) |
|
126 { |
|
127 hash += aKey[i]; |
|
128 } |
|
129 return hash % KFileHashMapEntries; |
|
130 } |
|
131 |
|
132 |
|
133 // |
|
134 // CCacheDirectoryEntry |
|
135 // |
|
136 |
|
137 CCacheDirectoryEntry* CCacheDirectoryEntry::NewL(const TDesC& aDirectory) |
|
138 { |
|
139 CCacheDirectoryEntry* self = new(ELeave) CCacheDirectoryEntry; |
|
140 CleanupStack::PushL(self); |
|
141 self->iDirectory = aDirectory.AllocL(); |
|
142 CleanupStack::Pop(self); |
|
143 return self; |
|
144 } |
|
145 |
|
146 CCacheDirectoryEntry::CCacheDirectoryEntry() |
|
147 { |
|
148 } |
|
149 |
|
150 CCacheDirectoryEntry::~CCacheDirectoryEntry() |
|
151 { |
|
152 delete iDirectory; |
|
153 } |
|
154 |
|
155 const TInt CCacheDirectoryEntry::iOffset = _FOFF(CCacheDirectoryEntry,iDlink); |
|
156 |
|
157 // |
|
158 // CApsRecognitionCache |
|
159 // |
|
160 |
|
161 CApsRecognitionCache::CApsRecognitionCache(RFs& aFs) |
|
162 : iFs(aFs), |
|
163 iDirectoryHeader(CCacheDirectoryEntry::iOffset), |
|
164 iIter(iDirectoryHeader) |
|
165 { |
|
166 } |
|
167 |
|
168 CApsRecognitionCache::~CApsRecognitionCache() |
|
169 { |
|
170 CCacheDirectoryEntry* anyitem; |
|
171 |
|
172 iIter.SetToFirst(); |
|
173 while ((anyitem = iIter++) != NULL) |
|
174 { |
|
175 anyitem->iDlink.Deque(); |
|
176 delete anyitem; |
|
177 }; |
|
178 } |
|
179 |
|
180 /** |
|
181 Adds a recognition result to the cache. An object is not added, when an up-to-date |
|
182 version is already in the cache or if it's not possible to check the file's LastModified(). |
|
183 @internalComponent |
|
184 */ |
|
185 void CApsRecognitionCache::AddL(const TDesC& aDirectory, const TDesC& aFileName, const TDataRecognitionResult& aRecognitionResult) |
|
186 { |
|
187 TTime lastModified; |
|
188 TFileName fullFileName(aDirectory); |
|
189 fullFileName.Append(aFileName); |
|
190 if(iFs.Modified(fullFileName, lastModified) != KErrNone) |
|
191 { |
|
192 #if defined(_DEBUG) |
|
193 RDebug::Print(_L("CApsRecognitionCache::AddL(): File '%S' was not added to the cache, cannot get the modified attribute (full filename is required for the cache to work)."), &fullFileName); |
|
194 #endif |
|
195 return; |
|
196 } |
|
197 DoAddL(aDirectory, aFileName, lastModified, aRecognitionResult); |
|
198 } |
|
199 |
|
200 /** |
|
201 Adds a recognition result to the cache. An object is not added, when an up-to-date |
|
202 version is already in the cache or if it's not possible to check the file's LastModified(). |
|
203 @internalComponent |
|
204 */ |
|
205 void CApsRecognitionCache::AddL(const RFile& aFile, const TDesC& aDirectory, const TDesC& aFileName, const TDataRecognitionResult& aRecognitionResult) |
|
206 { |
|
207 TTime lastModified; |
|
208 if(aFile.Modified(lastModified) != KErrNone) |
|
209 { |
|
210 #if defined(_DEBUG) |
|
211 TFileName fullFileName(aDirectory); |
|
212 fullFileName.Append(aFileName); |
|
213 RDebug::Print(_L("CApsRecognitionCache::AddL(): File '%S' was not added to the cache, cannot get the modified attribute."), &fullFileName); |
|
214 #endif |
|
215 return; |
|
216 } |
|
217 DoAddL(aDirectory, aFileName, lastModified, aRecognitionResult); |
|
218 } |
|
219 |
|
220 /** |
|
221 Adds a recognition result to the cache. An object is not added, when an up-to-date |
|
222 version is already in the cache or if it's not possible to check the file's LastModified(). |
|
223 @internalComponent |
|
224 */ |
|
225 void CApsRecognitionCache::DoAddL(const TDesC& aDirectory, const TDesC& aFileName, const TTime& aLastModified, const TDataRecognitionResult& aRecognitionResult) |
|
226 { |
|
227 if(iNumberOfEntries > KMaxNumberOfEntries) |
|
228 { |
|
229 Cleanup(); |
|
230 } |
|
231 |
|
232 CCacheDirectoryEntry* entry = NULL; |
|
233 iIter.SetToFirst(); |
|
234 while ((entry = iIter++) != NULL) |
|
235 { |
|
236 if(CompareDirectories(entry->Directory(),aDirectory)) |
|
237 { |
|
238 // move directory to top (it is likely to be used again soon) |
|
239 entry->iDlink.Deque(); |
|
240 iDirectoryHeader.AddFirst(*entry); |
|
241 break; |
|
242 } |
|
243 } |
|
244 |
|
245 if(!entry) |
|
246 { |
|
247 // create directory and append it |
|
248 entry = CCacheDirectoryEntry::NewL(aDirectory); |
|
249 iDirectoryHeader.AddFirst(*entry); |
|
250 } |
|
251 |
|
252 // insert to correct directory |
|
253 if(entry->Files().AddL(aFileName, aLastModified, aRecognitionResult)) |
|
254 { |
|
255 iNumberOfEntries++; |
|
256 } |
|
257 } |
|
258 |
|
259 /** |
|
260 Searches the cache for the particular recognition result. If the file was not modified since the |
|
261 file was recognized, the stored recognition result is returned. |
|
262 @internalComponent |
|
263 */ |
|
264 TBool CApsRecognitionCache::Get(const TDesC& aDirectory, const TDesC& aFileName, TDataRecognitionResult& aRecognitionResult) |
|
265 { |
|
266 TTime lastModified; |
|
267 TFileName fileName(aDirectory); |
|
268 fileName.Append(aFileName); |
|
269 const TInt error = iFs.Modified(fileName, lastModified); |
|
270 if(error != KErrNone) |
|
271 { |
|
272 return EFalse; |
|
273 } |
|
274 |
|
275 CRecognitionResult* result = DoGet(aDirectory, aFileName, lastModified); |
|
276 if(result) |
|
277 { |
|
278 result->Get(aRecognitionResult); |
|
279 result->Close(); // decrease reference count since we're not exposing the object |
|
280 return ETrue; |
|
281 } |
|
282 return EFalse; |
|
283 } |
|
284 |
|
285 /** |
|
286 Searches the cache for the particular recognition result. If the file was not modified since the |
|
287 file was recognized, the stored recognition result is returned. |
|
288 |
|
289 N.B. The returned value is reference counted! |
|
290 @internalComponent |
|
291 */ |
|
292 CRecognitionResult* CApsRecognitionCache::Get(const RFile& aFile, const TDesC& aDirectory, const TDesC& aFileName) |
|
293 { |
|
294 TTime lastModified; |
|
295 const TInt error = aFile.Modified(lastModified); |
|
296 if(error != KErrNone) |
|
297 { |
|
298 return NULL; |
|
299 } |
|
300 |
|
301 return DoGet(aDirectory, aFileName, lastModified); |
|
302 } |
|
303 |
|
304 /** |
|
305 Searches the cache for the particular recognition result. If the file was not modified since the |
|
306 file was recognized, the stored recognition result is returned. |
|
307 |
|
308 N.B. The returned value is reference counted! |
|
309 @internalComponent |
|
310 */ |
|
311 CRecognitionResult* CApsRecognitionCache::DoGet(const TDesC& aDirectory, const TDesC& aFileName, const TTime& aLastModified) |
|
312 { |
|
313 CRecognitionResult* result = NULL; |
|
314 CCacheDirectoryEntry* entry; |
|
315 |
|
316 iIter.SetToFirst(); |
|
317 while ((entry = iIter++) != NULL) |
|
318 { |
|
319 if(CompareDirectories(entry->Directory(),aDirectory)) |
|
320 { |
|
321 TTime cachedLastModified; |
|
322 result = entry->Files().Get(aFileName, cachedLastModified); |
|
323 if(result) |
|
324 { |
|
325 if(cachedLastModified != aLastModified) |
|
326 { |
|
327 result->Close(); |
|
328 result = NULL; |
|
329 } |
|
330 } |
|
331 |
|
332 // move directory to top (it is likely to be used again soon) |
|
333 entry->iDlink.Deque(); |
|
334 iDirectoryHeader.AddFirst(*entry); |
|
335 break; |
|
336 } |
|
337 } |
|
338 return result; |
|
339 } |
|
340 |
|
341 /** |
|
342 A fast comparison of two directory names. |
|
343 Should be faster than the "normal" TDesC16::Compare function, because |
|
344 there is no need to check which string is "greater". |
|
345 @internalComponent |
|
346 */ |
|
347 TBool CApsRecognitionCache::CompareDirectories(const TDesC& aDir1, const TDesC& aDir2) const |
|
348 { |
|
349 TBool equal = ETrue; |
|
350 if(aDir1.Length() == aDir2.Length()) |
|
351 { |
|
352 // start with the last character, as directories tend to be the same at the beginning |
|
353 for(TInt i=aDir1.Length()-1; i>=0; i--) |
|
354 { |
|
355 if(aDir1[i] != aDir2[i]) |
|
356 { |
|
357 // return as soon one character is "wrong" |
|
358 equal = EFalse; |
|
359 break; |
|
360 } |
|
361 } |
|
362 } |
|
363 else |
|
364 { |
|
365 equal = EFalse; |
|
366 } |
|
367 return equal; |
|
368 } |
|
369 /** |
|
370 Removes the least-often used directory in the cache. |
|
371 @internalComponent |
|
372 */ |
|
373 void CApsRecognitionCache::Cleanup() |
|
374 { |
|
375 CCacheDirectoryEntry* item = iDirectoryHeader.Last(); |
|
376 iNumberOfEntries -= item->NumberOfEntries(); |
|
377 item->iDlink.Deque(); |
|
378 delete item; |
|
379 } |
|
380 |
|
381 /** |
|
382 Empties the cache. Useful mainly for testing. |
|
383 @internalComponent |
|
384 */ |
|
385 void CApsRecognitionCache::Flush() |
|
386 { |
|
387 while(!iDirectoryHeader.IsEmpty()) |
|
388 { |
|
389 Cleanup(); |
|
390 } |
|
391 } |