|
1 // Copyright (c) 1996-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 <e32std.h> |
|
17 #include "server.h" |
|
18 #include "inifile.h" |
|
19 |
|
20 // uncomment so that if the wsini.ini file is not found on drive Wserv loaded from or drive Z: (if different) |
|
21 // it will be searched for on drive C: (if different from Wserv's drive) |
|
22 //#define LOAD_INI_FILE_FROM_DRIVE_Z_OR_C |
|
23 |
|
24 |
|
25 GLREF_D CDebugLogBase *wsDebugLog; |
|
26 |
|
27 _LIT(KDefaultSectionName,"DEFAULT"); |
|
28 _LIT(KCommentMarker,"//"); |
|
29 _LIT(KScreenSectionName,"SCREEN"); |
|
30 const TUint16 KNewSection('['); |
|
31 const TUint16 KSpaceChar(' '); |
|
32 const TUint16 KNewSection2(']'); |
|
33 const TInt KDefaultSectionNumber(0); |
|
34 const TInt KDefaultScreenId(-1); |
|
35 |
|
36 |
|
37 CIniFile::CIniFile() |
|
38 {} |
|
39 |
|
40 CIniFile::~CIniFile() |
|
41 { |
|
42 FreeData(); |
|
43 } |
|
44 |
|
45 CIniSection * CIniFile::FindSection(TInt aScreen) |
|
46 { |
|
47 for (TInt sect = 0; sect < iSectionArray.Count(); ++sect) |
|
48 { |
|
49 if (iSectionArray[sect]->Screen() == aScreen) |
|
50 { |
|
51 return iSectionArray[sect]; |
|
52 } |
|
53 } |
|
54 return NULL; |
|
55 } |
|
56 |
|
57 CIniSection * CIniFile::FindSection(const TDesC& aName) |
|
58 { |
|
59 for (TInt sect = 0; sect < iSectionArray.Count(); ++sect) |
|
60 { |
|
61 if (iSectionArray[sect]->Screen() == KDefaultScreenId && !iSectionArray[sect]->Name().CompareF(aName)) |
|
62 { |
|
63 return iSectionArray[sect]; |
|
64 } |
|
65 } |
|
66 return NULL; |
|
67 } |
|
68 |
|
69 /* Processes a .ini file entry section name. |
|
70 |
|
71 @return the corresponding index. |
|
72 @param aLine Input line of text from the .ini file, stripped of comments & excess whitespace. |
|
73 @leave KErrNoMemory |
|
74 */ |
|
75 CIniSection * CIniFile::AddOrFindIniSectionL(TPtr& aSectionName) |
|
76 { |
|
77 aSectionName.Trim(); |
|
78 |
|
79 // DEFAULT section |
|
80 if (aSectionName.CompareF(KDefaultSectionName) == 0) |
|
81 { |
|
82 return iSectionArray[KDefaultSectionNumber]; |
|
83 } |
|
84 |
|
85 // SCREENx section |
|
86 if (0 == aSectionName.FindF(KScreenSectionName)) |
|
87 { |
|
88 TLex lex(aSectionName.Mid(KScreenSectionName().Length())); |
|
89 TInt screenNum; |
|
90 lex.SkipSpace(); |
|
91 if (lex.Val(screenNum) == KErrNone) |
|
92 { |
|
93 return AddOrFindScreenSectionL(screenNum); |
|
94 } |
|
95 } |
|
96 |
|
97 // other section |
|
98 return AddOrFindNamedSectionL(aSectionName); |
|
99 } |
|
100 |
|
101 CIniSection * CIniFile::CreateSectionL(TInt aScreen) |
|
102 { |
|
103 CIniSection* newSection = new (ELeave) CIniSection(aScreen); |
|
104 CleanupStack::PushL( newSection ) ; |
|
105 newSection->ConstructL() ; |
|
106 User::LeaveIfError(iSectionArray.Append(newSection)); |
|
107 CleanupStack::Pop( newSection ) ; |
|
108 if (aScreen + 1 > iScreenCount) |
|
109 iScreenCount = aScreen + 1; |
|
110 return newSection; |
|
111 } |
|
112 |
|
113 CIniSection * CIniFile::CreateSectionL(const TDesC& aName) |
|
114 { |
|
115 CIniSection* newSection = new (ELeave) CIniSection(KDefaultScreenId); |
|
116 CleanupStack::PushL( newSection ) ; |
|
117 newSection->ConstructL(aName) ; |
|
118 User::LeaveIfError(iSectionArray.Append(newSection)); |
|
119 CleanupStack::Pop( newSection ) ; |
|
120 return newSection; |
|
121 } |
|
122 |
|
123 |
|
124 void CIniFile::doConstructL(RFile &aFile) |
|
125 { |
|
126 TFileText textFile; |
|
127 textFile.Set(aFile); |
|
128 const TInt KMaxIniLine=256; |
|
129 TBuf<KMaxIniLine> readLine; |
|
130 TBool first=ETrue; |
|
131 |
|
132 // always have a [DEFAULT] section |
|
133 CIniSection * currentSection = CreateSectionL(KDefaultSectionName); |
|
134 |
|
135 FOREVER |
|
136 { |
|
137 TInt err=textFile.Read(readLine); |
|
138 if (err==KErrEof) |
|
139 break; |
|
140 User::LeaveIfError(err); |
|
141 |
|
142 if (readLine.Length()>0) |
|
143 { |
|
144 if (first && (readLine[0]==0xFFFE || readLine[0]==0xFEFF)) |
|
145 readLine.Delete(0,1); |
|
146 |
|
147 // Comment marker "//" indicates the rest of the line should be discarded |
|
148 TInt commentStart = readLine.Find(KCommentMarker); |
|
149 if (commentStart != KErrNotFound) |
|
150 { |
|
151 readLine.Delete(commentStart, readLine.Length()); |
|
152 } |
|
153 |
|
154 // compact unnecessary whitespace |
|
155 readLine.TrimAll(); |
|
156 |
|
157 // anything left in buffer? |
|
158 if (readLine.Length() > 0) |
|
159 { |
|
160 // section name requires "[" and "]" |
|
161 if (readLine[0] == KNewSection && readLine.LocateReverse(KNewSection2) == readLine.Length() - 1) |
|
162 { |
|
163 TPtr nameText = readLine.MidTPtr(1, readLine.Length() - 2); // strip [ and ] |
|
164 currentSection = AddOrFindIniSectionL(nameText); |
|
165 } |
|
166 else |
|
167 { |
|
168 if (currentSection) |
|
169 { |
|
170 currentSection->AddVariableL(readLine); |
|
171 } |
|
172 } |
|
173 } |
|
174 first=EFalse; |
|
175 } |
|
176 } |
|
177 |
|
178 if (iScreenCount == 0) |
|
179 { |
|
180 iScreenCount = 1; |
|
181 } |
|
182 } |
|
183 |
|
184 CIniFile* CIniFile::NewL() |
|
185 { |
|
186 CIniFile* self = new (ELeave) CIniFile(); |
|
187 CleanupStack::PushL(self); |
|
188 self->ConstructL(); |
|
189 CleanupStack::Pop(self); |
|
190 return self; |
|
191 } |
|
192 |
|
193 void CIniFile::FreeData() |
|
194 { |
|
195 iSectionArray.ResetAndDestroy() ; |
|
196 iScreenCount = 0; |
|
197 } |
|
198 |
|
199 void errFreeData(TAny *aIniFile) |
|
200 { |
|
201 ((CIniFile *)aIniFile)->FreeData(); |
|
202 } |
|
203 |
|
204 HBufC* IniFileSearchPathLC() |
|
205 { |
|
206 _LIT(KPath,"\\SYSTEM\\DATA\\"); |
|
207 _LIT(KPathSep,";"); |
|
208 const TInt KLengthPerPath = 2 + KPath().Length(); |
|
209 // work out which drive Wserv loaded from |
|
210 RProcess self; |
|
211 TFileName myPath = self.FileName(); |
|
212 TParsePtrC myDrive(myPath); |
|
213 TDriveUnit myDriveUnit(myDrive.Drive()); |
|
214 // need extra buffer space for search paths for drives Z: or C: ? |
|
215 #if defined(LOAD_INI_FILE_FROM_DRIVE_Z_OR_C) |
|
216 TInt numPaths = 2; |
|
217 if (myDriveUnit != EDriveZ && myDriveUnit != EDriveC) |
|
218 { |
|
219 numPaths += 1; |
|
220 } |
|
221 #else |
|
222 TInt numPaths = 1; |
|
223 if (myDriveUnit != EDriveZ) |
|
224 { |
|
225 numPaths += 1; |
|
226 } |
|
227 #endif |
|
228 HBufC* searchPath = HBufC::NewLC(numPaths * KLengthPerPath + (numPaths - 1) * KPathSep().Length()); |
|
229 TPtr pPath(searchPath->Des()); |
|
230 pPath.Append(myDrive.Drive()); |
|
231 pPath.Append(KPath); |
|
232 if (myDriveUnit != EDriveZ) |
|
233 { |
|
234 pPath.Append(KPathSep); |
|
235 pPath.Append(TDriveUnit(EDriveZ).Name()); |
|
236 pPath.Append(KPath); |
|
237 } |
|
238 #if defined(LOAD_INI_FILE_FROM_DRIVE_Z_OR_C) |
|
239 if (myDriveUnit != EDriveC) |
|
240 { |
|
241 pPath.Append(KPathSep); |
|
242 pPath.Append(TDriveUnit(EDriveC).Name()); |
|
243 pPath.Append(KPath); |
|
244 } |
|
245 #endif |
|
246 return searchPath; |
|
247 } |
|
248 |
|
249 void CIniFile::ConstructL() |
|
250 { |
|
251 TAutoClose<RFs> fs; |
|
252 User::LeaveIfError(fs.iObj.Connect()); |
|
253 fs.iObj.SetNotifyUser(EFalse); |
|
254 fs.PushL(); |
|
255 HBufC* searchPath = IniFileSearchPathLC(); |
|
256 _LIT(KFileName,"WSINI.INI"); |
|
257 TFindFile findinifile(fs.iObj); |
|
258 TInt err=findinifile.FindByPath(KFileName,searchPath); |
|
259 User::LeaveIfError(err); |
|
260 CleanupStack::PopAndDestroy(searchPath); |
|
261 TAutoClose<RFile> file; |
|
262 User::LeaveIfError(file.iObj.Open(fs.iObj,findinifile.File(),EFileStreamText|EFileRead)); |
|
263 file.PushL(); |
|
264 CleanupStack::PushL(TCleanupItem(errFreeData,this)); |
|
265 doConstructL(file.iObj); |
|
266 CleanupStack::Pop(); // TCleanupItem |
|
267 file.Pop(); |
|
268 fs.Pop(); |
|
269 } |
|
270 |
|
271 /* If the Section for the screen exists find the data, otherwise create a new data structure. |
|
272 |
|
273 @param aScreen Screen number |
|
274 @return index to section |
|
275 @leave KErrNoMemory |
|
276 */ |
|
277 CIniSection * CIniFile::AddOrFindScreenSectionL(TInt aScreen) |
|
278 { |
|
279 CIniSection * section = FindSection(aScreen); |
|
280 if (!section) |
|
281 section = CreateSectionL(aScreen); |
|
282 return section; |
|
283 } |
|
284 |
|
285 /* If the Section exists find the data, otherwise create a new data structure. |
|
286 |
|
287 @param aName section name |
|
288 @return index to section |
|
289 @leave KErrNoMemory |
|
290 */ |
|
291 CIniSection * CIniFile::AddOrFindNamedSectionL(const TDesC& aName) |
|
292 { |
|
293 CIniSection * section = FindSection(aName); |
|
294 if (!section) |
|
295 section = CreateSectionL(aName); |
|
296 return section; |
|
297 } |
|
298 |
|
299 TBool CIniFile::FindVar(const TDesC &aVarName, TPtrC &aResult) |
|
300 { |
|
301 return iSectionArray[KDefaultSectionNumber]->FindVar(aVarName, aResult); |
|
302 } |
|
303 |
|
304 |
|
305 TBool CIniFile::FindVar(const TDesC &aVarName, TInt &aResult) |
|
306 { |
|
307 return iSectionArray[KDefaultSectionNumber]->FindVar(aVarName, aResult); |
|
308 } |
|
309 |
|
310 TBool CIniFile::FindVar(const TDesC &aVarName) |
|
311 // |
|
312 // Used to simply detect the presence of the specified variable name |
|
313 // |
|
314 { |
|
315 TPtrC ptr(NULL,0); |
|
316 return FindVar(aVarName, ptr); |
|
317 } |
|
318 |
|
319 // FindVar in [SCREENx] sections |
|
320 TBool CIniFile::FindVar( TInt aScreen, const TDesC &aVarName) |
|
321 { |
|
322 TPtrC ptr(NULL,0); |
|
323 return FindVar(aScreen, aVarName, ptr); |
|
324 } |
|
325 |
|
326 TBool CIniFile::FindVar( TInt aScreen, const TDesC& aVarName, TPtrC &aResult ) |
|
327 { |
|
328 CIniSection * section = FindSection(aScreen); |
|
329 TBool found = EFalse; |
|
330 if (section) |
|
331 found = section->FindVar(aVarName, aResult); |
|
332 if (!found) |
|
333 found = FindVar(aVarName, aResult); |
|
334 return found; |
|
335 } |
|
336 |
|
337 TBool CIniFile::FindVar(TInt aScreen, const TDesC &aVarName, TInt &aResult) |
|
338 { |
|
339 CIniSection * section = FindSection(aScreen); |
|
340 TBool found = EFalse; |
|
341 if (section) |
|
342 found = section->FindVar(aVarName, aResult); |
|
343 if (!found) |
|
344 found = FindVar(aVarName, aResult); |
|
345 return found; |
|
346 } |
|
347 |
|
348 // FindVar in named sections |
|
349 TBool CIniFile::FindVar(const TDesC& aSectionName, const TDesC &aVarName) |
|
350 { |
|
351 TPtrC ptr(NULL,0); |
|
352 return FindVar(aSectionName, aVarName, ptr); |
|
353 } |
|
354 |
|
355 TBool CIniFile::FindVar(const TDesC& aSectionName, const TDesC& aVarName, TPtrC &aResult ) |
|
356 { |
|
357 CIniSection * section = FindSection(aSectionName); |
|
358 TBool found = EFalse; |
|
359 if (section) |
|
360 found = section->FindVar(aVarName, aResult); |
|
361 if (!found) |
|
362 found = FindVar(aVarName, aResult); |
|
363 return found; |
|
364 } |
|
365 |
|
366 TBool CIniFile::FindVar(const TDesC& aSectionName, const TDesC &aVarName, TInt &aResult) |
|
367 { |
|
368 CIniSection * section = FindSection(aSectionName); |
|
369 TBool found = EFalse; |
|
370 if (section) |
|
371 found = section->FindVar(aVarName, aResult); |
|
372 if (!found) |
|
373 found = FindVar(aVarName, aResult); |
|
374 return found; |
|
375 } |
|
376 |
|
377 TInt CIniFile::NumberOfScreens() const |
|
378 { |
|
379 return iScreenCount; |
|
380 } |
|
381 |
|
382 |
|
383 // CIniSection. |
|
384 // ini file structure is now in sections like this |
|
385 // |
|
386 // [DEFAULT] |
|
387 // varname value |
|
388 // varname2 value2 |
|
389 // [SCREEN0] |
|
390 // screenvar value |
|
391 // etc |
|
392 // |
|
393 // CIniSection represents a section - i.e. section name and content pairs. |
|
394 // Content pairs are as ini file was previously (so use same code) |
|
395 // [default] section name is optional to support backwards compatibility |
|
396 // if no sutable value is found in a [screenN] section the [default] section will be searched. |
|
397 |
|
398 |
|
399 CIniSection::CIniSection(TInt aScreen) : iScreen(aScreen) |
|
400 {} |
|
401 |
|
402 void CIniSection::ConstructL() |
|
403 { |
|
404 iPtrArray = new (ELeave) CArrayPtrFlat<TDesC>(8) ; |
|
405 } |
|
406 |
|
407 void CIniSection::ConstructL(const TDesC& aName) |
|
408 { |
|
409 iName.CreateL(aName); |
|
410 ConstructL(); |
|
411 } |
|
412 |
|
413 CIniSection::~CIniSection() |
|
414 { |
|
415 iName.Close(); |
|
416 iPtrArray->ResetAndDestroy() ; |
|
417 delete iPtrArray ; |
|
418 } |
|
419 |
|
420 inline TInt CIniSection::Screen() const |
|
421 { return iScreen; } |
|
422 |
|
423 inline const TDesC& CIniSection::Name() const |
|
424 { return iName; } |
|
425 |
|
426 TBool CIniSection::FindVar( const TDesC& aVarName, TPtrC &aResult ) |
|
427 { |
|
428 if (iPtrArray) |
|
429 { |
|
430 TInt index(KErrNotFound); |
|
431 |
|
432 if (FindVarName(aVarName, index)) |
|
433 { |
|
434 TLex lex((*iPtrArray)[index]->Mid(aVarName.Length())); |
|
435 lex.SkipSpace(); |
|
436 aResult.Set(lex.Remainder()); |
|
437 |
|
438 if (wsDebugLog) |
|
439 { |
|
440 wsDebugLog->IniFileSettingRead(iScreen, aVarName, ETrue, aResult); |
|
441 } |
|
442 return(ETrue); |
|
443 } |
|
444 } |
|
445 |
|
446 if (wsDebugLog) |
|
447 { |
|
448 wsDebugLog->IniFileSettingRead(iScreen, aVarName, EFalse, KNullDesC); |
|
449 } |
|
450 return(EFalse); |
|
451 } |
|
452 |
|
453 /* |
|
454 create a TPtrC with just the first word (variable name) in the given string |
|
455 */ |
|
456 TPtrC CIniSection::VarName(const TDesC& aVarString) |
|
457 { |
|
458 TInt varLength = aVarString.Locate(KSpaceChar); |
|
459 if (varLength == KErrNotFound) |
|
460 { |
|
461 varLength = aVarString.Length(); |
|
462 } |
|
463 return aVarString.Left(varLength); |
|
464 } |
|
465 |
|
466 |
|
467 TBool CIniSection::FindVar(const TDesC &aVarName, TInt &aResult) |
|
468 { |
|
469 TPtrC ptr(NULL,0); |
|
470 // do text Find |
|
471 if (FindVar(aVarName, ptr)) |
|
472 { |
|
473 TLex lex(ptr); |
|
474 _LIT(HexFormatCheck,"0x"); |
|
475 TPtrC hexPtr(HexFormatCheck); |
|
476 if(ptr.Left(2) != hexPtr) |
|
477 { |
|
478 if (lex.Val(aResult) == KErrNone) |
|
479 { |
|
480 return ETrue; |
|
481 } |
|
482 } |
|
483 else |
|
484 { |
|
485 lex.SkipAndMark(2); //To skip 0x in hex code |
|
486 if (lex.Val((TUint32&)aResult, EHex) == KErrNone) |
|
487 { |
|
488 return ETrue; |
|
489 } |
|
490 } |
|
491 } |
|
492 |
|
493 return EFalse; |
|
494 } |
|
495 |
|
496 |
|
497 /* |
|
498 Find variable name in sorted array, using binary search |
|
499 @param aVarName variable name to search for, must have any space and variable value stripped. |
|
500 @param aIndex output index of matching or preceeding item |
|
501 @return |
|
502 */ |
|
503 TBool CIniSection::FindVarName(const TDesC& aVarName, TInt& aIndex) |
|
504 { |
|
505 // Binary Search |
|
506 // left is lowest index to include, right is highest index + 1; |
|
507 TInt left = 0; |
|
508 TInt right = iPtrArray->Count(); |
|
509 |
|
510 while (right > left) |
|
511 { |
|
512 TInt middle = (left + right)>>1; |
|
513 // compare to start of variable string |
|
514 TPtrC cmpString = VarName(*(*iPtrArray)[middle]); |
|
515 TInt cmp = aVarName.CompareF(cmpString); |
|
516 |
|
517 if (cmp == 0) |
|
518 { |
|
519 aIndex = middle; |
|
520 return ETrue; |
|
521 } |
|
522 else if (cmp > 0) |
|
523 { |
|
524 left = middle + 1; |
|
525 } |
|
526 else |
|
527 { |
|
528 right = middle; |
|
529 } |
|
530 } |
|
531 |
|
532 aIndex = right; |
|
533 return EFalse; |
|
534 } |
|
535 |
|
536 void CIniSection::AddVariableL(const TDesC& aNewVariable) |
|
537 { |
|
538 // use variable name only for search |
|
539 TPtrC varName = VarName(aNewVariable); |
|
540 TInt index(0); |
|
541 |
|
542 // ignore duplicate definitions |
|
543 if (0 == FindVarName(varName, index)) |
|
544 { // insert in sorted array |
|
545 HBufC* hbuf = aNewVariable.AllocLC() ; |
|
546 iPtrArray->InsertL(index, hbuf); |
|
547 CleanupStack::Pop(hbuf); |
|
548 } |
|
549 } |
|
550 |