|
1 /* |
|
2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Bitmap animator INI file handler |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 #include "CBmpAnimIniData.h" |
|
23 |
|
24 #include <f32file.h> |
|
25 #include <e32std.h> |
|
26 |
|
27 // Default directory to look for INI file |
|
28 _LIT(KIniFileDir,"C:\\private\\100056cf\\"); |
|
29 |
|
30 const TInt KTokenSize=32; |
|
31 |
|
32 #ifdef _DEBUG |
|
33 // Debugging aids |
|
34 enum TIniPanic |
|
35 { |
|
36 ESectionNameTooBig, |
|
37 EKeyNameTooBig, |
|
38 }; |
|
39 |
|
40 void Panic(TIniPanic aPanic) |
|
41 { |
|
42 _LIT(CBmpAnimIniData,"CBmpAnimIniData"); |
|
43 User::Panic(CBmpAnimIniData,aPanic); |
|
44 } |
|
45 #endif // _DEBUG |
|
46 |
|
47 // d'tor |
|
48 CBmpAnimIniData::~CBmpAnimIniData() |
|
49 { |
|
50 delete (TText*)iPtr.Ptr(); |
|
51 delete iToken; |
|
52 delete iName; |
|
53 } |
|
54 |
|
55 |
|
56 // Public allocation method |
|
57 CBmpAnimIniData* CBmpAnimIniData::NewL(const TDesC& aName) |
|
58 { |
|
59 CBmpAnimIniData* p=new(ELeave) CBmpAnimIniData; |
|
60 CleanupStack::PushL(p); |
|
61 p->ConstructL(aName); |
|
62 CleanupStack::Pop(); |
|
63 return p; |
|
64 } |
|
65 |
|
66 |
|
67 // Find a key's string) value regardless of section (wide) |
|
68 TBool CBmpAnimIniData::FindVar(const TDesC8& aKeyName, TDes16& aResult) |
|
69 { |
|
70 TPtrC8 tmpRes; |
|
71 if (!FindVar(aKeyName, tmpRes)) |
|
72 { |
|
73 return EFalse; |
|
74 } |
|
75 |
|
76 // Copy the 8-bit result into the 16-bit descriptor |
|
77 aResult.Copy(tmpRes); |
|
78 return ETrue; |
|
79 } |
|
80 |
|
81 |
|
82 // Find a key's (string) value regardless of section |
|
83 TBool CBmpAnimIniData::FindVar(const TDesC8& aKeyName, TPtrC8& aResult) |
|
84 { |
|
85 _LIT8(KDummySection, ""); |
|
86 // Call with no section, so starts at beginning |
|
87 if (FindVar(KDummySection, aKeyName, aResult)) |
|
88 { |
|
89 return ETrue; |
|
90 } |
|
91 else |
|
92 { |
|
93 return EFalse; |
|
94 } |
|
95 } |
|
96 |
|
97 |
|
98 // Find a key's (string) value given a section name and a key name (wide) |
|
99 TBool CBmpAnimIniData::FindVar(const TDesC8& aSectName, |
|
100 const TDesC8& aKeyName, |
|
101 TDes16& aResult) |
|
102 { |
|
103 TPtrC8 tmpRes; |
|
104 if (!FindVar(aSectName, aKeyName, tmpRes)) |
|
105 { |
|
106 return EFalse; |
|
107 } |
|
108 |
|
109 // Copy the 8-bit result into the 16-bit descriptor |
|
110 aResult.Copy(tmpRes); |
|
111 return ETrue; |
|
112 } |
|
113 |
|
114 |
|
115 // Find a key's (string) value given a section name and a key name |
|
116 TBool CBmpAnimIniData::FindVar(const TDesC8& aSectName, |
|
117 const TDesC8& aKeyName, |
|
118 TPtrC8& aResult) |
|
119 { |
|
120 __ASSERT_DEBUG(aSectName.Length() <= KTokenSize, Panic(ESectionNameTooBig)); |
|
121 __ASSERT_DEBUG(aKeyName.Length() <= KTokenSize, Panic(EKeyNameTooBig)); |
|
122 |
|
123 TInt posStartOfSection(0); |
|
124 TInt posEndOfSection(0); |
|
125 TPtrC8 SearchBuf; |
|
126 |
|
127 // If we have a section, set pos to section start |
|
128 if (aSectName.Length() > 0) |
|
129 { |
|
130 if (!FindSection(aSectName, posStartOfSection, posEndOfSection)) |
|
131 { |
|
132 return EFalse; |
|
133 } |
|
134 } |
|
135 |
|
136 // Look for key in ini file data Buffer |
|
137 TInt posI = posStartOfSection; // Position in internal data Buffer |
|
138 TBool FoundKey(EFalse); |
|
139 while (!FoundKey) |
|
140 { |
|
141 // Search for next occurrence of aKeyName |
|
142 SearchBuf.Set(iPtr.Mid(posI)); |
|
143 TInt posSB = SearchBuf.Find(aKeyName); |
|
144 |
|
145 // If not found, return |
|
146 if (posSB == KErrNotFound) |
|
147 { |
|
148 return EFalse; |
|
149 } |
|
150 |
|
151 // Check this is at beginning of line (ie. non-commented) |
|
152 // ie. Check preceding char was CR or LF |
|
153 if(posSB > 0) |
|
154 { |
|
155 // Create a Buffer, starting one char before found subBuf |
|
156 TPtrC8 CharBefore(SearchBuf.Right(SearchBuf.Length() - posSB + 1)); |
|
157 // Check first char is end of prev |
|
158 if(CharBefore[0] == '\n') |
|
159 { |
|
160 FoundKey = ETrue; |
|
161 posI = posI + posSB; |
|
162 } |
|
163 else |
|
164 { |
|
165 posI = posI + posSB + 1; |
|
166 } |
|
167 } |
|
168 else |
|
169 { |
|
170 FoundKey = ETrue; |
|
171 } |
|
172 |
|
173 } // while (!FoundKey) |
|
174 |
|
175 // Set pos to just after '=' sign |
|
176 SearchBuf.Set(iPtr.Mid(posI)); |
|
177 TInt posSB = SearchBuf.Locate('='); |
|
178 if (posSB == KErrNotFound) // Illegal format, should flag this... |
|
179 { |
|
180 return EFalse; |
|
181 } |
|
182 |
|
183 // Identify start and end of data (EOL or EOF) |
|
184 posI = posI + posSB + 1; // 1 char after '=' |
|
185 TInt posValStart = posI; |
|
186 TInt posValEnd; |
|
187 SearchBuf.Set(iPtr.Mid(posI)); |
|
188 posSB = SearchBuf.Locate('\r'); |
|
189 if (posSB != KErrNotFound) |
|
190 { |
|
191 posValEnd = posI + posSB; |
|
192 } |
|
193 else |
|
194 { |
|
195 posValEnd = iPtr.Length(); |
|
196 } |
|
197 |
|
198 // Check we are still in the section requested |
|
199 if (aSectName.Length() > 0) |
|
200 { |
|
201 if (posValEnd > posEndOfSection) |
|
202 { |
|
203 return EFalse; |
|
204 } |
|
205 } |
|
206 |
|
207 // Parse Buffer from posn of key |
|
208 // Start one space after '=' |
|
209 TLex8 lex(iPtr.Mid(posValStart, posValEnd - posValStart)); |
|
210 lex.SkipSpaceAndMark(); // Should be at the start of the data |
|
211 aResult.Set(lex.MarkedToken().Ptr(), |
|
212 posValEnd - posValStart - lex.Offset()); |
|
213 |
|
214 return ETrue; |
|
215 } |
|
216 |
|
217 |
|
218 // Find integer value regardless of section |
|
219 TBool CBmpAnimIniData::FindVar(const TDesC8& aKeyName, TInt& aResult) |
|
220 { |
|
221 TPtrC8 ptr(NULL, 0); |
|
222 if (FindVar(aKeyName, ptr)) |
|
223 { |
|
224 TLex8 lex(ptr); |
|
225 if (lex.Val(aResult) == KErrNone) |
|
226 { |
|
227 return ETrue; |
|
228 } |
|
229 } |
|
230 return EFalse; |
|
231 } |
|
232 |
|
233 |
|
234 // Find integer value within a given section |
|
235 TBool CBmpAnimIniData::FindVar( |
|
236 const TDesC8& aSection, const TDesC8& aKeyName, TInt& aResult) |
|
237 { |
|
238 TPtrC8 ptr(NULL, 0); |
|
239 if (FindVar(aSection, aKeyName, ptr)) |
|
240 { |
|
241 TLex8 lex(ptr); |
|
242 if (lex.Val(aResult) == KErrNone) |
|
243 { |
|
244 return ETrue; |
|
245 } |
|
246 } |
|
247 return EFalse; |
|
248 } |
|
249 |
|
250 |
|
251 // Write integer value in given section |
|
252 TInt CBmpAnimIniData::WriteVarL( |
|
253 const TDesC8& aSection, const TDesC8& aKeyName, TInt aValue) |
|
254 { |
|
255 TBuf8<32> buf; |
|
256 buf.Num(aValue); |
|
257 return WriteVarL(aSection, aKeyName, buf); |
|
258 } |
|
259 |
|
260 |
|
261 // Write string value in given section |
|
262 TInt CBmpAnimIniData::WriteVarL( |
|
263 const TDesC8& aSection, const TDesC8& aKeyName, const TDesC8& aValue) |
|
264 { |
|
265 // First find the variable - this gives us a descriptor into the |
|
266 // ini data giving the bound of the item that has to be replaced |
|
267 TPtrC8 ptr; |
|
268 TInt pos; |
|
269 TBool found = FindVar(aSection, aKeyName, ptr); |
|
270 |
|
271 HBufC8* text = HBufC8::NewLC( |
|
272 aSection.Length() + aKeyName.Length() + aValue.Length() + 7); // +7 for '=', '[', ']' and 2*cr+lf. |
|
273 TPtr8 textp = text->Des(); |
|
274 |
|
275 if (found) |
|
276 { |
|
277 pos = ptr.Ptr() - iPtr.Ptr(); |
|
278 textp.Append(aValue); |
|
279 } |
|
280 else |
|
281 { |
|
282 TInt posStartOfSection = 0; |
|
283 TInt posEndOfSection = 0; |
|
284 |
|
285 if (FindSection(aSection, posStartOfSection, posEndOfSection)) |
|
286 { |
|
287 pos = posEndOfSection; |
|
288 } |
|
289 else |
|
290 { |
|
291 pos = iPtr.Length(); |
|
292 textp.Append('['); |
|
293 textp.Append(aSection); |
|
294 textp.Append(']'); |
|
295 textp.Append('\r'); |
|
296 textp.Append('\n'); |
|
297 } |
|
298 textp.Append(aKeyName); |
|
299 textp.Append('='); |
|
300 textp.Append(aValue); |
|
301 textp.Append('\r'); |
|
302 textp.Append('\n'); |
|
303 } |
|
304 |
|
305 TInt size = (iPtr.Length() + textp.Length() - ptr.Length()) * sizeof(TText8); |
|
306 |
|
307 if (size > iPtr.MaxLength()) |
|
308 { |
|
309 TText8* newdata = (TText8*) User::ReAllocL((TUint8*)iPtr.Ptr(), size); |
|
310 iPtr.Set(newdata, iPtr.Length(), size/sizeof(TText8)); |
|
311 } |
|
312 |
|
313 iPtr.Replace(pos, ptr.Length(), textp); |
|
314 |
|
315 CleanupStack::PopAndDestroy(text); |
|
316 |
|
317 return KErrNone; |
|
318 } |
|
319 |
|
320 |
|
321 // Commits the changes in variables, ie writes the file data (held in iPtr) |
|
322 // into the actual disk file |
|
323 void CBmpAnimIniData::CommitL() |
|
324 { |
|
325 TAutoClose<RFs> fs; |
|
326 User::LeaveIfError(fs.iObj.Connect()); |
|
327 fs.PushL(); |
|
328 |
|
329 // Just replace the file with the data, no seeking necessary |
|
330 TAutoClose<RFile> file; |
|
331 file.iObj.Replace(fs.iObj, *iName, EFileStreamText|EFileWrite); |
|
332 file.PushL(); |
|
333 |
|
334 TPtrC8 ptrc8((TUint8*)iPtr.Ptr(), iPtr.Size()); |
|
335 User::LeaveIfError(file.iObj.Write(ptrc8)); |
|
336 |
|
337 file.Pop(); |
|
338 fs.Pop(); |
|
339 } |
|
340 |
|
341 |
|
342 // --- protected --- |
|
343 |
|
344 // c'tor |
|
345 CBmpAnimIniData::CBmpAnimIniData() |
|
346 : iPtr(NULL, 0) |
|
347 { |
|
348 __DECLARE_NAME(_S("CBmpAnimIniData")); |
|
349 } |
|
350 |
|
351 |
|
352 // Allocate a buffer and Read file's contents into iPtr |
|
353 void CBmpAnimIniData::ConstructL(const TDesC& aName) |
|
354 { |
|
355 // Allocate space for token |
|
356 iToken = HBufC8::NewL(KTokenSize + 2); // 2 extra chars for [tokenName] |
|
357 |
|
358 // Connect to file server |
|
359 TAutoClose<RFs> fs; |
|
360 User::LeaveIfError(fs.iObj.Connect()); |
|
361 fs.PushL(); |
|
362 |
|
363 // Find file, given name |
|
364 TFindFile ff(fs.iObj); |
|
365 TAutoClose<RFile> file; |
|
366 TInt err = ff.FindByDir(aName, KIniFileDir); |
|
367 |
|
368 // If found - cool, use the found file's name and open it |
|
369 if (err == KErrNone) |
|
370 { |
|
371 iName = ff.File().AllocL(); |
|
372 err = file.iObj.Open(fs.iObj, *iName, EFileStreamText | EFileRead); |
|
373 } |
|
374 |
|
375 // If not found - create the file using the given name |
|
376 if (err == KErrNotFound) |
|
377 { |
|
378 err = file.iObj.Create(fs.iObj, aName, EFileStreamText); |
|
379 iName = aName.AllocL(); |
|
380 } |
|
381 |
|
382 file.PushL(); |
|
383 |
|
384 // Get file size and read in as 8-bit data |
|
385 TInt size = 0; |
|
386 User::LeaveIfError(file.iObj.Size(size)); |
|
387 TText8* data = (TText8*) User::AllocL(size); |
|
388 iPtr.Set(data, size, size); |
|
389 TPtr8 dest((TUint8*)data, 0, size); |
|
390 User::LeaveIfError(file.iObj.Read(dest)); |
|
391 |
|
392 file.Pop(); |
|
393 fs.Pop(); |
|
394 } |
|
395 |
|
396 |
|
397 // --- private --- |
|
398 |
|
399 |
|
400 // Find a section in the INIfile |
|
401 TBool CBmpAnimIniData::FindSection( |
|
402 const TDesC8& aSection, TInt& aStart, TInt& aEnd) |
|
403 { |
|
404 TInt posI = 0; // Position in internal databuffer |
|
405 TBool FoundSection = EFalse; |
|
406 TPtrC8 SearchBuf; |
|
407 |
|
408 while (!FoundSection) |
|
409 { |
|
410 // Move search buffer to next area of interest |
|
411 SearchBuf.Set(iPtr.Mid(posI)); |
|
412 |
|
413 // Make up token "[SECTIONNAME]", to search for |
|
414 TPtr8 sectionToken = iToken->Des(); |
|
415 _LIT8(sectionTokenFmtString,"[%S]"); |
|
416 sectionToken.Format(sectionTokenFmtString, &aSection); |
|
417 |
|
418 // Search for next occurrence of aSection |
|
419 TInt posSB = SearchBuf.Find(sectionToken); |
|
420 |
|
421 // If not found, return |
|
422 if (posSB == KErrNotFound) |
|
423 { |
|
424 return EFalse; |
|
425 } |
|
426 |
|
427 // Check this is at beginning of line (ie. non-commented) |
|
428 // ie. Check preceding char was LF |
|
429 if (posSB > 0) |
|
430 { |
|
431 // Create a Buffer, starting one char before found subBuf |
|
432 TPtrC8 CharBefore(SearchBuf.Right(SearchBuf.Length() - posSB + 1)); |
|
433 // Check first char is end of prev |
|
434 if (CharBefore[0] == '\n') |
|
435 { |
|
436 FoundSection = ETrue; // found |
|
437 posI = posI + posSB; |
|
438 } |
|
439 else |
|
440 { |
|
441 posI = posI + posSB + 1; // try again |
|
442 } |
|
443 } |
|
444 else |
|
445 { |
|
446 FoundSection = ETrue; |
|
447 } |
|
448 |
|
449 } // while (!FoundSection) |
|
450 |
|
451 // Set start of section, after section name, (incl '[' and ']') |
|
452 aStart = posI + aSection.Length() + 2; |
|
453 |
|
454 // Set end of section, by finding begin of next section or end |
|
455 SearchBuf.Set(iPtr.Mid(posI)); |
|
456 |
|
457 _LIT8(nextSectionBuf,"\n["); |
|
458 |
|
459 TInt posSB = SearchBuf.Find(nextSectionBuf); |
|
460 if (posSB != KErrNotFound) |
|
461 { |
|
462 aEnd = posI + posSB + 1; |
|
463 } |
|
464 else |
|
465 { |
|
466 aEnd = iPtr.Length(); |
|
467 } |
|
468 |
|
469 return ETrue; |
|
470 } |
|
471 |
|
472 // EOF |