lowlevellibsandfws/apputils/src/BAUTILS.CPP
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     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 // Started by DWW, November 1995
       
    15 // BAFL utilities static class
       
    16 //
       
    17 //
       
    18 
       
    19 #include "BaUtilsImp.h"
       
    20 #include <e32hal.h>
       
    21 #include <bautils.h>
       
    22 #include <baflpan.h>
       
    23 #include <baliba.h>
       
    24 #include <hal.h>
       
    25 #include <hal_data.h>
       
    26 #include <utf.h>
       
    27 
       
    28 /**
       
    29 Mimimum length of a filename and mimimum length of a suffix.
       
    30 Note these two values are tied together.
       
    31 */
       
    32 const TInt KInvNameAndMinSuffixLength = 2;
       
    33 
       
    34 #define ISDIGIT(c) (c-'0' >= 0 && c-'0' <= 9)
       
    35 
       
    36 _LIT(KAllDrives, "YXWVUTSRQPONMLKJIHGFEDCBAZ");
       
    37 const TInt KDriveAndPathLength = 3;
       
    38 
       
    39 // screen calibration stuff
       
    40 _LIT(KScreenCalibrationFolder,"\\System\\Data\\");
       
    41 _LIT(KScreenCalibrationFileName, "Screen.DAT");
       
    42 const TInt KScreenCalibrationPathLength = 23;	// folder + filename
       
    43 
       
    44 
       
    45 // #define DO_PROFILING
       
    46 
       
    47 #if defined(DO_PROFILING)
       
    48 #pragma message ("------------ N.B. profiling of \"BaflUtils::NearestLanguageFile\" is enabled")
       
    49 #include <e32svr.h>
       
    50 #define FIRST_PROFILE_INDEX	50
       
    51 #define PROFILE_INDEX_1		(FIRST_PROFILE_INDEX+0)
       
    52 #define PROFILE_COUNT		1
       
    53 #endif
       
    54 
       
    55 // BaflUtils
       
    56 
       
    57 class BaflDir : public CDir
       
    58 	{
       
    59 public:
       
    60 	void RemoveSystem();
       
    61 	TInt SortByTable(CBaflFileSortTable* aTable);
       
    62 private:
       
    63 	TInt MinEntrySize(const TEntry & aEntry);
       
    64 	};
       
    65 
       
    66 
       
    67 LOCAL_C const TLanguage dp0[] = { ELangCanadianEnglish, ELangAmerican,ELangEnglish, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangEnglish_Prc,ELangEnglish_Japan,ELangEnglish_Thailand,ELangEnglish_India,ELangAustralian,ELangNewZealand,ELangInternationalEnglish,ELangSouthAfricanEnglish,ELangNone };
       
    68 LOCAL_C const TLanguage dp1[] = { ELangAmerican, ELangEnglish,ELangCanadianEnglish, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangEnglish_Prc,ELangEnglish_Japan,ELangEnglish_Thailand,ELangEnglish_India,ELangAustralian,ELangNewZealand,ELangInternationalEnglish,ELangSouthAfricanEnglish, ELangNone };
       
    69 LOCAL_C const TLanguage dp2[] = { ELangAustralian, ELangEnglish, ELangAmerican, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangEnglish_Prc,ELangEnglish_Japan,ELangEnglish_Thailand,ELangEnglish_India,ELangNewZealand,ELangInternationalEnglish,ELangSouthAfricanEnglish, ELangCanadianEnglish,ELangNone };
       
    70 LOCAL_C const TLanguage dp3[] = { ELangSouthAfricanEnglish, ELangEnglish, ELangAustralian, ELangAmerican, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangEnglish_Prc,ELangEnglish_Japan,ELangEnglish_Thailand,ELangEnglish_India,ELangNewZealand,ELangInternationalEnglish,ELangCanadianEnglish,ELangNone };
       
    71 LOCAL_C const TLanguage dp4[] = { ELangInternationalEnglish, ELangEnglish, ELangAustralian, ELangAmerican, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangEnglish_Prc,ELangEnglish_Japan,ELangEnglish_Thailand,ELangEnglish_India,ELangNewZealand,ELangSouthAfricanEnglish,ELangCanadianEnglish,ELangNone };
       
    72 LOCAL_C const TLanguage dp5[] = { ELangEnglish_Apac, ELangEnglish, ELangAustralian, ELangAmerican,ELangInternationalEnglish,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangEnglish_Prc,ELangEnglish_Japan,ELangEnglish_Thailand,ELangEnglish_India,ELangNewZealand,ELangSouthAfricanEnglish,ELangCanadianEnglish,ELangNone };
       
    73 LOCAL_C const TLanguage dp6[] = { ELangEnglish_Taiwan, ELangEnglish, ELangAustralian, ELangAmerican, ELangEnglish_Apac,ELangInternationalEnglish,ELangEnglish_HongKong,ELangEnglish_Prc,ELangEnglish_Japan,ELangEnglish_Thailand,ELangEnglish_India,ELangNewZealand,ELangSouthAfricanEnglish,ELangCanadianEnglish,ELangNone };
       
    74 LOCAL_C const TLanguage dp7[] = { ELangEnglish_HongKong, ELangEnglish, ELangAustralian, ELangAmerican, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangInternationalEnglish,ELangEnglish_Prc,ELangEnglish_Japan,ELangEnglish_Thailand,ELangEnglish_India,ELangNewZealand,ELangSouthAfricanEnglish,ELangCanadianEnglish,ELangNone };
       
    75 LOCAL_C const TLanguage dp8[] = { ELangEnglish_Prc, ELangEnglish, ELangAustralian, ELangAmerican, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangInternationalEnglish,ELangEnglish_Japan,ELangEnglish_Thailand,ELangEnglish_India,ELangNewZealand,ELangSouthAfricanEnglish,ELangCanadianEnglish,ELangNone };
       
    76 LOCAL_C const TLanguage dp9[] = { ELangEnglish_Japan, ELangEnglish, ELangAustralian, ELangAmerican, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangEnglish_Prc,ELangInternationalEnglish,ELangEnglish_Thailand,ELangEnglish_India,ELangNewZealand,ELangSouthAfricanEnglish,ELangCanadianEnglish,ELangNone };
       
    77 LOCAL_C const TLanguage dp10[] = { ELangEnglish_Thailand, ELangEnglish, ELangAustralian, ELangAmerican, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangEnglish_Prc,ELangEnglish_Japan,ELangInternationalEnglish,ELangEnglish_India,ELangNewZealand,ELangSouthAfricanEnglish,ELangCanadianEnglish,ELangNone };
       
    78 LOCAL_C const TLanguage dp11[] = { ELangEnglish_India, ELangEnglish, ELangAustralian, ELangAmerican, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangEnglish_Prc,ELangEnglish_Japan,ELangEnglish_Thailand,ELangInternationalEnglish,ELangNewZealand,ELangSouthAfricanEnglish,ELangCanadianEnglish,ELangNone };
       
    79 LOCAL_C const TLanguage dp12[] = { ELangNewZealand, ELangEnglish, ELangAmerican, ELangEnglish_Apac,ELangEnglish_Taiwan,ELangEnglish_HongKong,ELangEnglish_Prc,ELangEnglish_Japan,ELangEnglish_Thailand,ELangEnglish_India,ELangAustralian,ELangInternationalEnglish,ELangSouthAfricanEnglish, ELangCanadianEnglish,ELangNone };
       
    80 LOCAL_C const TLanguage dp13[] = { ELangInternationalFrench,ELangFrench,ELangSwissFrench,ELangBelgianFrench,ELangCanadianFrench,ELangNone };
       
    81 LOCAL_C const TLanguage dp14[] = { ELangBelgianFrench, ELangFrench,ELangInternationalFrench,ELangSwissFrench,ELangCanadianFrench,ELangNone };
       
    82 LOCAL_C const TLanguage dp15[] = { ELangCanadianFrench, ELangFrench,ELangInternationalFrench,ELangSwissFrench,ELangBelgianFrench,ELangNone };
       
    83 LOCAL_C const TLanguage dp16[] = { ELangFrench,ELangInternationalFrench,ELangSwissFrench,ELangBelgianFrench,ELangCanadianFrench,ELangNone };
       
    84 LOCAL_C const TLanguage dp17[] = { ELangSwissFrench,ELangFrench,ELangInternationalFrench,ELangBelgianFrench,ELangCanadianFrench,ELangNone };
       
    85 LOCAL_C const TLanguage dp18[] = { ELangSwissGerman,ELangGerman,ELangAustrian,ELangNone };
       
    86 LOCAL_C const TLanguage dp19[] = { ELangAustrian,ELangGerman,ELangSwissGerman,ELangNone };
       
    87 LOCAL_C const TLanguage dp20[] = { ELangGerman,ELangSwissGerman,ELangAustrian,ELangNone };
       
    88 LOCAL_C const TLanguage dp21[] = { ELangSerbian,ELangCroatian,ELangNone };
       
    89 LOCAL_C const TLanguage dp22[] = { ELangCroatian,ELangSerbian,ELangNone };
       
    90 LOCAL_C const TLanguage dp23[] = { ELangRomanian,ELangMoldavian,ELangNone };
       
    91 LOCAL_C const TLanguage dp24[] = { ELangMoldavian,ELangRomanian,ELangNone };
       
    92 LOCAL_C const TLanguage dp25[] = { ELangBelgianFlemish,ELangDutch,ELangNone };
       
    93 LOCAL_C const TLanguage dp26[] = { ELangDutch,ELangBelgianFlemish,ELangNone };
       
    94 LOCAL_C const TLanguage dp27[] = { ELangAfrikaans,ELangDutch,ELangNone };
       
    95 LOCAL_C const TLanguage dp28[] = { ELangMalay_Apac,ELangMalay,ELangNone };
       
    96 LOCAL_C const TLanguage dp29[] = { ELangIndonesian_Apac,ELangIndonesian,ELangNone };
       
    97 LOCAL_C const TLanguage dp30[] = { ELangSpanish,ELangInternationalSpanish,ELangLatinAmericanSpanish,ELangNone };
       
    98 LOCAL_C const TLanguage dp31[] = { ELangLatinAmericanSpanish,ELangSpanish,ELangInternationalSpanish,ELangNone };
       
    99 LOCAL_C const TLanguage dp32[] = { ELangInternationalSpanish,ELangSpanish,ELangLatinAmericanSpanish,ELangNone };
       
   100 LOCAL_C const TLanguage dp33[] = { ELangCyprusGreek,ELangGreek,ELangNone };
       
   101 LOCAL_C const TLanguage dp34[] = { ELangGreek,ELangCyprusGreek,ELangNone };
       
   102 LOCAL_C const TLanguage dp35[] = { ELangSwissItalian,ELangItalian,ELangNone };
       
   103 LOCAL_C const TLanguage dp36[] = { ELangItalian,ELangSwissItalian,ELangNone };
       
   104 LOCAL_C const TLanguage dp37[] = { ELangBrazilianPortuguese,ELangPortuguese,ELangNone };
       
   105 LOCAL_C const TLanguage dp38[] = { ELangPortuguese,ELangBrazilianPortuguese,ELangNone };
       
   106 LOCAL_C const TLanguage dp39[] = { ELangFinlandSwedish,ELangSwedish,ELangNone };
       
   107 LOCAL_C const TLanguage dp40[] = { ELangSwedish,ELangFinlandSwedish,ELangNone };
       
   108 LOCAL_C const TLanguage dp41[] = { ELangCyprusTurkish,ELangTurkish,ELangNone };
       
   109 LOCAL_C const TLanguage dp42[] = { ELangTurkish,ELangCyprusTurkish,ELangNone };
       
   110 LOCAL_C const TLanguage dp43[] = { ELangHongKongChinese, ELangTaiwanChinese, ELangPrcChinese,ELangNone };
       
   111 LOCAL_C const TLanguage dp44[] = { ELangTaiwanChinese, ELangHongKongChinese,ELangPrcChinese,ELangNone };
       
   112 LOCAL_C const TLanguage dp45[] = { ELangPrcChinese, ELangHongKongChinese, ELangTaiwanChinese,ELangNone };
       
   113 LOCAL_C const TLanguage * const KEquivalentLists[] = { dp0,  dp1,  dp2,  dp3,  dp4,  dp5,  dp6,  
       
   114 		dp7,  dp8,  dp9,  dp10,  dp11,  dp12,  dp13,  dp14,  dp15,  dp16,  dp17,
       
   115 		dp18,  dp19,  dp20,  dp21,  dp22,  dp23,  dp24,  dp25,  dp26,  dp27,  
       
   116 		dp28,  dp29,  dp30,  dp31,  dp32,  dp33,  dp34,  dp35,  dp36,  dp37,  
       
   117 		dp38,  dp39,  dp40,  dp41,  dp42,  dp43,  dp44,  dp45};
       
   118 
       
   119 /**
       
   120 This function gets the list of languages that are 'equivalent' to the
       
   121 given language. We say language L1 is equivalent to language L2 if 
       
   122 speakers of L2 can readily understand L1 without intentional study 
       
   123 or extraordinary effort.
       
   124 
       
   125 The equivalence relationship is defined in a static table. Please refer 
       
   126 to the definition of 'KEquivalentLists' for details.
       
   127 Each row in the table is formatted like this:
       
   128 @code
       
   129 L1, L2, L3, ..., Ln, ELangNone
       
   130 @codeend
       
   131 In which L2, ..., Ln are equivalents of L1, and ELangNone marks the end of an
       
   132 entry. The list is ordered. Compared with L3, L2 is nearer to L1. When choosing
       
   133 an equivalent of L1, L2 shall be preferred over L3, L3 shall be preferred 
       
   134 over L4, and so on.  
       
   135 L1 is always returned as the ‘nearest equivalent’ of L1 itself.
       
   136 
       
   137 BaflUtils::NearestLanguageFileV2 searches language specific resource files 
       
   138 according to the 'equivalent' relationship returned by this function.
       
   139  
       
   140 @param aLang The language whose equivalents needs to be found out.
       
   141 @param aEquivalents On return, this array contains the ordered list of 
       
   142        languages that are equivalent to the given language. If there is no 
       
   143        entry for the given language in the table, this array will contain 
       
   144        two elements on return: the first is the given language itself 
       
   145        and the 2nd one is ELangNone. For any language that has equivalents 
       
   146        defined, content of he corresponding entry is returned.     
       
   147        
       
   148 @see BaflUtils::NearestLanguageFileV2
       
   149 */ 
       
   150 EXPORT_C void 
       
   151 BaflUtils::GetEquivalentLanguageList(TLanguage aLang, TLanguagePath& aEquivalents) 
       
   152 	{
       
   153 	aEquivalents[0] = aLang;
       
   154 	aEquivalents[1] = ELangNone;
       
   155 	const TInt len = sizeof(KEquivalentLists) / sizeof(KEquivalentLists[0]);
       
   156 	for (TInt i = 0; i < len; ++i)
       
   157 		{
       
   158 		const TLanguage *ptr = KEquivalentLists[i];
       
   159 		if (ptr[0] == aLang)
       
   160 			{
       
   161 			TInt index = 1;
       
   162 			while (ELangNone != *ptr)
       
   163 				{
       
   164 				aEquivalents[index++] = (TLanguage)*(++ptr);
       
   165 				}
       
   166 			aEquivalents[index] = ELangNone;
       
   167 			break;
       
   168 			} // end if ptr[0]
       
   169 		} // end for i
       
   170 	}
       
   171 
       
   172 /**
       
   173 NearestLanguageFileV2 is very similar to the existing 'NearestLanguageFile'
       
   174 function. The only difference between NearestLanguageFile and
       
   175 NearestLanguageFileV2 is the order in which language specific 
       
   176 resource files are searched for. 
       
   177 NearestLanguageFile searches language specific resource files in the 
       
   178 order defined by the 'downgrade path' of the given language. Content of the 
       
   179 downgrade path is dependent on the current active locale, and parts of 
       
   180 it is runtime configurable.
       
   181 NearestLanguageFileV2 searches for language specific resource files 
       
   182 in the order defined by the 'language equivalence table', which is a  
       
   183 static data table fixed at build time. There is one entry in the table for 
       
   184 each language that has one or more equivalents.
       
   185 
       
   186 @param aFs An active file server session.
       
   187 @param aName Name of the language-neutral resource file name which consist of
       
   188 an optional drive specification, followed by an optional path name,
       
   189 followed by basename for filename, followed by a period and extension.
       
   190 On return, in case of a match, this is replaced by the language-specific version
       
   191 which consists of the last two characters of the extension plus any preceding
       
   192 numeric characters being replaced by the language code. Remains unchanged when there's no match 
       
   193 @param aLanguage On return, in case of a match, this is replaced by the corresponding language.
       
   194   In case of no match, it is set to ELangNone.  
       
   195 
       
   196 @see TLanguage
       
   197 @see BaflUtils::GetEquivalentLanguageList
       
   198  */
       
   199 EXPORT_C void 
       
   200 BaflUtils::NearestLanguageFileV2(const RFs& aFs,TFileName& aName, TLanguage& aLanguage)
       
   201 	{
       
   202 	TNearestLanguageFileFinder finder(aFs);
       
   203 	TBool goodSuffix=finder.SetFileName(aName);
       
   204 	
       
   205 	// Continue only if the suffix is good.
       
   206 	if(goodSuffix)
       
   207 		{
       
   208 		// add preset customised resource drive to drive list  
       
   209 		// Note that errors returned from AddCustomResourceDrive are ignored. This is because if 
       
   210 		// a custom resource drive has not been found we still want to continue on with searching 
       
   211 		// other drives according to our algorithm
       
   212 		finder.AddCustomResourceDrive();
       
   213 		
       
   214 		GetEquivalentLanguageList(User::Language(), finder.iPath);
       
   215 		if (!finder.FindLanguageAndDrive()
       
   216 			&& KErrNone != finder.FindFirstLanguageFileAndDrive())
       
   217 			finder.RepairFileName();
       
   218 		aLanguage = finder.Language();
       
   219 		}
       
   220 	else
       
   221 		{
       
   222 		aLanguage = ELangNone;
       
   223 		}
       
   224 	}
       
   225 
       
   226 // TLibAssocBase
       
   227 
       
   228 EXPORT_C TLibAssocBase::TLibAssocBase(const RLibrary& aLib,TAny* aPtr)
       
   229 	: iLibrary(aLib),iPtr(aPtr)
       
   230 /**
       
   231 Constructs the object taking the specified DLL and a class instance.
       
   232 
       
   233 @param aLib A reference to a DLL that has already been opened.
       
   234 @param aPtr An untyped pointer to an object to be associated with the DLL.
       
   235             Typically, this object will have been created using
       
   236             the ordinal 1 function from that DLL. */	
       
   237 	{}
       
   238 
       
   239 
       
   240 
       
   241 
       
   242 EXPORT_C void TLibAssocBase::Set(const RLibrary& aLib,TAny* aPtr)
       
   243 /**
       
   244 Implements TLibAssoc::Set().
       
   245 
       
   246 @param aLib   A reference to a DLL that has already been opened.
       
   247 @param aClass A pointer to an object to be associated with the DLL.
       
   248               Typically, this object will have been created using
       
   249               the ordinal 1 function from that DLL.
       
   250 
       
   251 @see TLibAssoc::Set */
       
   252 	{
       
   253 	__ASSERT_ALWAYS(iLibrary.Handle()==KNullHandle&&iPtr==NULL,Panic(EBafPanicLibAssocAlreadySet));
       
   254 	iLibrary=aLib;
       
   255 	iPtr=aPtr;
       
   256 	}
       
   257 
       
   258 
       
   259 
       
   260 
       
   261 EXPORT_C void TLibAssocBase::DoUnload(TAny* aThis)
       
   262 /**
       
   263 Calls Close() on the associated DLL.
       
   264 
       
   265 @param aThis An untyped pointer to a TLibAssoc type.
       
   266 */
       
   267 	{
       
   268 	TLibAssocBase& l=*(TLibAssocBase*)aThis;
       
   269 	l.iPtr=NULL;
       
   270 	l.iLibrary.Close();
       
   271 	}
       
   272 
       
   273 //
       
   274 // class BaflUtils
       
   275 //
       
   276 EXPORT_C void BaflUtils::CopyWithTruncation(TDes& aDest,const TDesC& aSrc,TChar aTruncationSymbol)
       
   277 /** Copies a descriptor, abbreviating it to fit the destination descriptor.
       
   278 
       
   279 If aSrc is less than the maximum length of aDest, then the string is simply 
       
   280 copied to aDest.
       
   281 
       
   282 If this is not so, then the left-most characters of aSrc are copied to aDest, 
       
   283 up to aDest's maximum length-1. aDest's final character is set to be aTruncationSymbol.
       
   284 
       
   285 @param aDest On return, the truncated string
       
   286 @param aSrc The string to truncate
       
   287 @param aTruncationSymbol The truncation character to add */
       
   288 	{ // static
       
   289 	TInt maxLength=aDest.MaxLength();
       
   290 	if (aSrc.Length()<=maxLength)
       
   291 		aDest.Copy(aSrc);
       
   292 	else
       
   293 		{
       
   294 		aDest.Copy(aSrc.Left(maxLength-1));
       
   295 		aDest.Append(aTruncationSymbol);
       
   296 		}
       
   297 	}
       
   298 
       
   299 EXPORT_C TBool BaflUtils::FileExists(const RFs& aFileSession,const TDesC& aFileName)
       
   300 /** Checks if the specified file exists.
       
   301 	
       
   302 @param aFs File server session
       
   303 @param aFileName File to check
       
   304 @return ETrue if the file exists, otherwise EFalse */
       
   305 	{ // static
       
   306 	TEntry entry;
       
   307 	return(aFileSession.Entry(aFileName,entry)==KErrNone);
       
   308 	}
       
   309 
       
   310 EXPORT_C TBool BaflUtils::PathExists(RFs& aFs,const TDesC& aPath)
       
   311 /** Tests whether a path exists.
       
   312 
       
   313 The path should contain a drive letter and a directory, or EFalse is returned. 
       
   314 EFalse is also returned if it contains a filename or filename extension.
       
   315 
       
   316 If the path is badly formed, for instance if it contains illegal characters, 
       
   317 or any directory name consists of a single or double dot, or any directory 
       
   318 name includes wildcard characters, the function returns EFalse.
       
   319 
       
   320 @param aFs A connected session with the file server.
       
   321 @param aPath The path to test for. It should end in a backslash.
       
   322 @return ETrue if the path exists, EFalse if not. EFalse is also returned if the 
       
   323 specified path is badly formed. */
       
   324 	{ // static
       
   325 	TParse parse;
       
   326 	TInt retcode;
       
   327 	retcode = parse.Set(aPath, NULL, NULL);
       
   328 	if (retcode != KErrNone)
       
   329 		return EFalse;
       
   330 	if ((! parse.DrivePresent()) || (parse.NameOrExtPresent()))
       
   331 		return EFalse;
       
   332 	if (parse.Path().Length() == 0)
       
   333 		return EFalse;
       
   334 	TFileName dirName = parse.DriveAndPath();
       
   335 	if (dirName.Length() > KMaxFileName)
       
   336 		return(EFalse);
       
   337     RDir dir;
       
   338     retcode = dir.Open(aFs,dirName,0);
       
   339 	if (retcode == KErrNone)
       
   340 		dir.Close();
       
   341 	return (retcode == KErrNone);
       
   342 	}
       
   343 
       
   344 EXPORT_C void BaflUtils::EnsurePathExistsL(RFs& aFileSession,const TDesC& aFileName)
       
   345 /** Makes one or more directories, if they do not already exist. 
       
   346 	
       
   347 Any valid path component in the specified path that does not already exist 
       
   348 is created as a directory. If the specified path already exists, the function 
       
   349 returns normally.
       
   350 
       
   351 @param aFs File server session
       
   352 @param aFileName Path to ensure exists
       
   353 @see RFs::MkDirAll() */
       
   354 	{ // static
       
   355 	TInt error=aFileSession.MkDirAll(aFileName);
       
   356 	if (error!=KErrAlreadyExists)
       
   357 		User::LeaveIfError(error);
       
   358 	}
       
   359 
       
   360 EXPORT_C TPtrC BaflUtils::ExtractAppNameFromFullName(const TFullName &aName)
       
   361 /** Gets the application name from a full thread name.
       
   362 
       
   363 @param aName Thread name
       
   364 @return Application name
       
   365 @see RThread */
       
   366 	{
       
   367 	// static - return the app name (after first :: before next ::, if any) from a full thread name
       
   368 	TChar delimiter=':';
       
   369 	TInt start=aName.Locate(delimiter);
       
   370 	if (start<0)
       
   371 		start=0; // should never happen
       
   372 	else if (aName.Length()>start+2)
       
   373 		start+=2;
       
   374 	TPtrC rest=aName.Mid(start);
       
   375 	TInt end=rest.Locate(delimiter);
       
   376 	return end<0 ? rest : rest.Left(end);
       
   377 	}
       
   378 
       
   379 LOCAL_C TBool IsLanguageExtended(const TLanguage aLanguage)
       
   380 	{
       
   381 	// For compatibility reasons, ELangNone is 0xFFFF. However, it's not an extended language.
       
   382 	if ((aLanguage==ELangNone) || ((static_cast<TUint>(aLanguage))<=KDialectMask))
       
   383 		return EFalse;
       
   384 	else
       
   385 		return ETrue;
       
   386 	}
       
   387 
       
   388 
       
   389 LOCAL_C TLanguage BaseLanguage(const TLanguage aLanguage)
       
   390 	{
       
   391 	if (IsLanguageExtended(aLanguage))
       
   392 		return static_cast<TLanguage>(aLanguage & KDialectMask);
       
   393 	else
       
   394 		return aLanguage;
       
   395 	}
       
   396 
       
   397 LOCAL_C TLanguage NextLanguage(TLanguage aLanguage)
       
   398 /** Returns the next best language to use after aLanguage,
       
   399 based on Symbian's base table of language near-equivalence.
       
   400 @internalAll */
       
   401 	{
       
   402 	switch (aLanguage)
       
   403 		{
       
   404 		case ELangAustralian:
       
   405 		case ELangNewZealand:
       
   406 		case ELangSouthAfricanEnglish:
       
   407 		case ELangInternationalEnglish:
       
   408 		case ELangAmerican:
       
   409 		case ELangEnglish_Apac:
       
   410 		case ELangEnglish_Taiwan:
       
   411 		case ELangEnglish_HongKong:
       
   412 		case ELangEnglish_Prc:
       
   413 		case ELangEnglish_Japan:
       
   414 		case ELangEnglish_Thailand:
       
   415 			return ELangEnglish;
       
   416 		case ELangCanadianEnglish:
       
   417 			return ELangAmerican;	// 2-stage downgrade
       
   418 		case ELangSwissFrench:
       
   419 		case ELangBelgianFrench:
       
   420 		case ELangInternationalFrench:
       
   421 		case ELangCanadianFrench:
       
   422 			return ELangFrench;
       
   423 		case ELangSwissGerman:
       
   424 		case ELangAustrian:
       
   425 			return ELangGerman;
       
   426 		case ELangInternationalSpanish:
       
   427 		case ELangLatinAmericanSpanish:
       
   428 			return ELangSpanish;
       
   429 		case ELangSwissItalian:
       
   430 			return ELangItalian;
       
   431 		case ELangFinlandSwedish:
       
   432 			return ELangSwedish;
       
   433 		case ELangCyprusTurkish:
       
   434 			return ELangTurkish;
       
   435 		case ELangBelgianFlemish:
       
   436 			return ELangDutch;
       
   437 		case ELangHongKongChinese:
       
   438 			return ELangTaiwanChinese;
       
   439 		case ELangCyprusGreek:
       
   440 			return ELangGreek;
       
   441 		case ELangMalay_Apac:
       
   442 			return ELangMalay;
       
   443 		case ELangBrazilianPortuguese:
       
   444 			return ELangPortuguese;
       
   445 		default:
       
   446 			return ELangNone;	
       
   447 		}
       
   448 	}
       
   449 
       
   450 
       
   451 void AddLanguage(TLanguagePath& aPath, TLanguage aNewLanguage)
       
   452 /** Add language to the language path if there is space.
       
   453 The first empty slot must have "ELangNone" in it. This will also be true
       
   454 on exit. */	
       
   455 	{
       
   456 	TLanguage *p = aPath;
       
   457 	const TLanguage *end = &(aPath[KMaxDowngradeLanguages]);
       
   458 	while (p != end)
       
   459 		{
       
   460 		if (*p == aNewLanguage)
       
   461 			// language already in list
       
   462 			break;
       
   463 		if (*p == ELangNone)
       
   464 			{
       
   465 			// found the end of the list
       
   466 			p[0] = aNewLanguage;
       
   467 			p[1] = ELangNone;
       
   468 			break;
       
   469 			}
       
   470 		++p;
       
   471 		}
       
   472 	return;
       
   473 	}
       
   474 
       
   475 void MakeLanguageDowngradePath(TLanguagePath& aPath,
       
   476 	TLanguage aCurrent, TLanguage aIdeal, const TLocale& aLocale)
       
   477 	{
       
   478 	TInt j = 0;
       
   479 	if( aIdeal != ELangNone)
       
   480 		{
       
   481 		aPath[j++]=aIdeal;	
       
   482 		}
       
   483 	aPath[j++] = aCurrent;
       
   484 	aPath[j++] = ELangNone;
       
   485 
       
   486 	if (aCurrent & ~KDialectMask)
       
   487 		AddLanguage(aPath, static_cast<TLanguage>(aCurrent & KDialectMask));
       
   488 
       
   489 	for (TInt i=0;i<=2;i++)
       
   490 		{
       
   491 		AddLanguage(aPath, aLocale.LanguageDowngrade(i));
       
   492 		AddLanguage(aPath, BaseLanguage(aLocale.LanguageDowngrade(i)));
       
   493 		}
       
   494 
       
   495 	while (ELangNone != (aCurrent = NextLanguage(BaseLanguage(aCurrent))))  
       
   496 		AddLanguage(aPath, aCurrent);
       
   497 	}
       
   498 
       
   499 TInt RRealDirectoryScanner::Open(RFs& aFs, const TDesC& aMatchPattern)
       
   500 	{
       
   501 	return iDir.Open(aFs, aMatchPattern,
       
   502 		KEntryAttReadOnly | KEntryAttHidden | KEntryAttSystem | KEntryAttArchive);
       
   503 	}
       
   504 
       
   505 TInt RRealDirectoryScanner::Next(TEntry& aOut)
       
   506 	{
       
   507 	return iDir.Read(aOut);
       
   508 	}
       
   509 
       
   510 void RRealDirectoryScanner::Close()
       
   511 	{
       
   512 	iDir.Close();
       
   513 	}
       
   514 
       
   515 /**
       
   516 Simply counts the number of numerical characters at the end of the name passed.
       
   517 
       
   518 @internalComponent
       
   519 @param			aFilename The filename to parse
       
   520 				
       
   521 @return			Count of the numeric digits at the end of the name passed, 
       
   522 				e.g. x.r491 gives 3.
       
   523 */
       
   524 TInt TNearestLanguageFileFinder::CountDigitsFromEnd(const TDesC& aFilename)
       
   525 	{
       
   526 	TInt digitCount = 0;
       
   527 	
       
   528 	for (TInt idx = aFilename.Length()-1; idx>=0 && ISDIGIT (aFilename [idx]); --idx)
       
   529 		{
       
   530 		++digitCount;
       
   531 		}
       
   532 		
       
   533 	return digitCount;
       
   534 	}
       
   535 
       
   536 
       
   537 /**
       
   538 Counts the number of digits at the end of a filename.
       
   539 
       
   540 @internalComponent
       
   541 @param			aFilename The filename to parse
       
   542 				
       
   543 @return			Count of the numeric digits at the end of the suffix, 
       
   544 				e.g. x.r491 gives 3.
       
   545 				0 if no numeric end of suffix,
       
   546 				KErrBadName for an invalid filename,
       
   547 				KErrNotSupported if the filename (minus path) is less
       
   548 				than or equal to KInvNameAndMinSuffixLength in length
       
   549 */
       
   550 TInt TNearestLanguageFileFinder::CountDigitsFromEndInSuffix (const TDesC& aFilename)
       
   551 	{
       
   552 	TInt digitCount = 0;
       
   553 	TInt slashIdx = 0;
       
   554 	TInt len = aFilename.Length ();
       
   555 	
       
   556 	// NOTE: We didn't use TChar here as they are too slow.
       
   557 	// We also didn't use TParse as they are too large.
       
   558 	
       
   559 	// don't work on the path
       
   560 	for (slashIdx=len-1; slashIdx >= 0 && aFilename[slashIdx] != '\\'; --slashIdx)
       
   561 	{/*do nothing*/};
       
   562 	
       
   563 	// Get new length
       
   564 	if (slashIdx>=0) {len = len-slashIdx-1;}
       
   565 
       
   566 	// Initial test to see if filename legal size.
       
   567 	if (len > KInvNameAndMinSuffixLength)
       
   568 		{
       
   569 		digitCount = CountDigitsFromEnd(aFilename);
       
   570 
       
   571 		// Can't store something bigger or we'll panic!
       
   572 		if (digitCount > KMaxSuffixLength)
       
   573 			{
       
   574 			digitCount = KErrBadName;
       
   575 			}
       
   576 		else
       
   577 		// numeric filename, e.g. "1234". 
       
   578 		// No preceeding alpha character
       
   579 		if (!(len-digitCount))
       
   580 			{
       
   581 			digitCount = KErrBadName;
       
   582 			}
       
   583 		}
       
   584 	else
       
   585 		{
       
   586 		digitCount = KErrNotSupported;
       
   587 		}
       
   588 		
       
   589 	return digitCount;
       
   590 	}
       
   591 
       
   592 RDirectoryScanner& TNearestLanguageFileFinder::DirectoryScanner()
       
   593 	{
       
   594 	return iDirScanner;
       
   595 	}
       
   596 
       
   597 TBool TNearestLanguageFileFinder::FileExists(const TDesC& aFileName) const
       
   598 	{
       
   599 	return BaflUtils::FileExists(iFs, aFileName);
       
   600 	}
       
   601 
       
   602 TBool TNearestLanguageFileFinder::FindDrive()
       
   603 	{
       
   604 	ASSERT(iFileName);
       
   605 	TBool found=EFalse;
       
   606 	TInt driveLength=iDrives.Length();
       
   607 	for (TInt drive = 0; drive!=driveLength; ++drive)
       
   608 		{
       
   609 		(*iFileName)[0] = iDrives[drive];
       
   610 		if (FileExists(*iFileName))
       
   611 			{
       
   612 			found=ETrue;
       
   613 			break;
       
   614 			}
       
   615 		}
       
   616 	return found;
       
   617 	}
       
   618 
       
   619 TBool TNearestLanguageFileFinder::AppendLanguageCode(TLanguage aLanguage)
       
   620 	{
       
   621 	TInt rest = static_cast<TInt>(aLanguage);
       
   622 #ifdef _DEBUG
       
   623 	_LIT(KErrorMessage, "Bafl");
       
   624 #endif
       
   625 	__ASSERT_DEBUG(0 <= rest, User::Panic(KErrorMessage,KErrArgument));
       
   626 	iFileName->SetLength(iBaseLength);
       
   627 	const TInt remaining = iFileName->MaxLength() - iBaseLength;
       
   628 	TInt soFar = 0;
       
   629 	TBuf<1> num;
       
   630 	num.Append('0');
       
   631 	TBool appendLangSuccess = ETrue;
       
   632 	TInt digitCount = 0;
       
   633 	TInt digit = 0;
       
   634 	while (rest)
       
   635 		{
       
   636 		if (remaining == soFar)
       
   637 			{
       
   638 			// no more room in descriptor- return rather than panic,
       
   639 			// file cannot exist.
       
   640 			iFileName->SetLength(iBaseLength);
       
   641 			appendLangSuccess= EFalse;
       
   642 			break;
       
   643 			}
       
   644 		// Convert the number to ASCII by consistantly getting the base 10 remainder to convert.
       
   645 		// The number is updated minus the remainder for the next iteration.
       
   646 		// eg (rest = 123) -> (12, r3) -> (1, r2) -> (0, r1)
       
   647 		// Then insert the ASCII representation of the remainder into the filename end
       
   648 		// so it appears the correct way round.
       
   649 		// eg (filename.r) -> (filename.r3) -> (filename.r23) -> (filename.r123)
       
   650 		digit = rest % 10;
       
   651 		digitCount++;
       
   652 		rest /= 10;
       
   653 		num[0] = static_cast<TText16>(digit + '0');
       
   654 		iFileName->Insert(iBaseLength, num);
       
   655 
       
   656 		// Minimum suffix length is KInvNameAndMinSuffixLength
       
   657 		// so we have to insert zeros to make this up.
       
   658 		while (!rest && digitCount < KInvNameAndMinSuffixLength)
       
   659 			{
       
   660 			num[0] = static_cast<TText16>('0');
       
   661 			iFileName->Insert(iBaseLength, num);
       
   662 			++digitCount;
       
   663 			}
       
   664 			
       
   665 		++soFar;
       
   666 		}
       
   667 		
       
   668 	return appendLangSuccess;
       
   669 	}
       
   670 
       
   671 
       
   672 TBool TNearestLanguageFileFinder::FindLanguageAndDrive()
       
   673 /** Search for files across all drives in all languages in the path plus the
       
   674 language-neutral file. */
       
   675 	{
       
   676 	ASSERT(iFileName);
       
   677 	// No point appending if the suffix is bad
       
   678 	for (const TLanguage* currentLang = iPath; *currentLang != ELangNone; ++currentLang)
       
   679 		{
       
   680 		if (AppendLanguageCode(*currentLang) && FindDrive())
       
   681 			{
       
   682 			iLanguage = *currentLang;
       
   683 			return ETrue;
       
   684 			}
       
   685 		}
       
   686 	// search for language-neutral file
       
   687 	iFileName->SetLength(iBaseLength);
       
   688 	iFileName->Append(iSuffix);
       
   689 	return FindDrive();
       
   690 	}
       
   691 
       
   692 TInt TNearestLanguageFileFinder::LanguageNumberFromFile(const TDesC& aFileName, const TDesC& aStem)
       
   693 	{
       
   694 	TInt lang = 0;
       
   695 	TInt multiplier = 1;
       
   696 	TInt leadingZeroCount = 0;
       
   697 	TInt languageNumber = KErrNotFound;
       
   698 	const TText* firstChar = aFileName.Ptr();
       
   699 	const TText* lastChar = firstChar + aFileName.Length() - 1;
       
   700 	const TText* currentChar = lastChar;
       
   701 	// string cannot contain only numbers, because it must have a ':' in it
       
   702 	while ('0' <= *currentChar && *currentChar <= '9')
       
   703 		{
       
   704 		if (*currentChar == '0')
       
   705 			leadingZeroCount++;
       
   706 		else
       
   707 			{
       
   708 			leadingZeroCount = 0;
       
   709 			lang += multiplier * (*currentChar - '0');
       
   710 			}
       
   711 		multiplier *= 10;
       
   712 		--currentChar;
       
   713 		}
       
   714 	TInt along=lastChar - currentChar;
       
   715 	if (2 <= along)
       
   716 		{
       
   717 		// We have at least 2 digits at the end.
       
   718 		// trim of bad leading zeros
       
   719 		TInt maxTrim = along - 2;
       
   720 		if (maxTrim < leadingZeroCount)
       
   721 			{
       
   722 			leadingZeroCount = maxTrim;
       
   723 			}
       
   724 		currentChar += leadingZeroCount;
       
   725 		// we have at least 2 digits at the end but does the rest of it match the stem?
       
   726 		TPtrC foundStem(firstChar, currentChar - firstChar + 1);
       
   727 		//foundStem.CompareF(aStem.Right(foundStem.Length()))
       
   728 		if (0 == foundStem.CompareF(aStem))
       
   729 			{
       
   730 			languageNumber=lang;
       
   731 			}
       
   732 		}
       
   733 	return languageNumber;
       
   734 	}
       
   735 
       
   736 TInt TNearestLanguageFileFinder::FindFirstLanguageFile(RFs& aFs)
       
   737 	{
       
   738 	ASSERT(iFileName);
       
   739 	iFileName->SetLength(iBaseLength);
       
   740 	TPtrC name(*iFileName);
       
   741 	TParsePtrC nameToParse(name);
       
   742 	TPtrC nameStem(nameToParse.NameAndExt());
       
   743 	iFileName->Append('*');
       
   744 	TInt bestLanguageMatch = KMaxTInt;
       
   745 	RDirectoryScanner& scanner = DirectoryScanner();
       
   746 	TInt err = scanner.Open(aFs, *iFileName);
       
   747 	if (err != KErrNone)
       
   748 		{
       
   749 		return err;
       
   750 		}
       
   751 	TEntry entry;
       
   752 	while (KErrNone == scanner.Next(entry))
       
   753 		{
       
   754 		TInt lang = LanguageNumberFromFile(entry.iName, nameStem);
       
   755 		if (0 < lang && lang < bestLanguageMatch)
       
   756 			{
       
   757 			bestLanguageMatch = lang;
       
   758 			}
       
   759 		}
       
   760 	scanner.Close();
       
   761 	if (bestLanguageMatch != KMaxTInt)
       
   762 		{
       
   763 		iLanguage = static_cast<TLanguage>(bestLanguageMatch);
       
   764 		AppendLanguageCode(static_cast<TLanguage>(bestLanguageMatch));
       
   765 		return KErrNone;
       
   766 		}
       
   767 	return KErrNotFound;
       
   768 	}
       
   769 
       
   770 // Try each drive for any language files
       
   771 // iFileName must have a directory specifier
       
   772 TInt TNearestLanguageFileFinder::FindFirstLanguageFileAndDrive()
       
   773 	{
       
   774 	ASSERT(iFileName);
       
   775 	TInt findFirstResult=KErrNotFound;
       
   776 	TInt driveLength=iDrives.Length();
       
   777 	for (TInt drive = 0; drive != driveLength; ++drive)
       
   778 		{
       
   779 		(*iFileName)[0] = iDrives[drive];
       
   780 		TInt err = FindFirstLanguageFile(CONST_CAST(RFs&,iFs));
       
   781 		if (err == KErrNone || err == KErrNoMemory)
       
   782 			{
       
   783 			findFirstResult=err;
       
   784 			break;
       
   785 			}
       
   786 		}
       
   787 	return findFirstResult;
       
   788 	}
       
   789 
       
   790 /**
       
   791 Invalid filenames are any filename whose length (minus path) must be greater
       
   792 than KInvNameAndMinSuffixLength, and whose form is purely numerical, i.e. '1234' 
       
   793 */
       
   794 TBool TNearestLanguageFileFinder::SetFileName(TFileName& aFileName)
       
   795 	{
       
   796 	iDrives.Zero();
       
   797 	iFileName = &aFileName;
       
   798 	iOriginalBaseLength = iFileName->Length();
       
   799 	
       
   800 	TInt suffixLength = CountDigitsFromEndInSuffix (aFileName);
       
   801 	
       
   802 	// No point trying for filenames thats are badly formed
       
   803 	// or that are too large.
       
   804 	if (suffixLength >= 0 && 
       
   805 		KInvNameAndMinSuffixLength < iOriginalBaseLength)
       
   806 		{
       
   807 		if (suffixLength > 0)
       
   808 			{
       
   809 			// all of suffix to be replaced 
       
   810 			iSuffix = iFileName->Right(suffixLength);
       
   811 			iOriginalBaseLength -= suffixLength;
       
   812 			iFileName->SetLength(iOriginalBaseLength);
       
   813 			}
       
   814 		else
       
   815 			{ 
       
   816 			// No numerical part to suffix
       
   817 			TInt periodIdx = 0;
       
   818 			
       
   819 			// Search for the period within range KInvNameAndMinSuffixLength 
       
   820 			// from the end. As this must work for all values of
       
   821 			// KInvNameAndMinSuffixLength
       
   822 			for (TInt i = iOriginalBaseLength-1; 
       
   823 			     !periodIdx && i >= (iOriginalBaseLength-KInvNameAndMinSuffixLength-1);
       
   824 			     --i)
       
   825 				{
       
   826 				if ((*iFileName) [i] == '.')
       
   827 					{
       
   828 					periodIdx = i;
       
   829 					}
       
   830 				}
       
   831 			
       
   832 			// Don't handle files ending in a period.
       
   833 			// This is because the behaviour is different between Windows
       
   834 			// and Symbian Fs. In Windows it strips the period off.
       
   835 			//
       
   836 			// However, and this shouldn't happen as it is not shown
       
   837 			// (in the documentation) to be valid.
       
   838 			// Just try our best.
       
   839 			if (periodIdx == iOriginalBaseLength-1)
       
   840 				{
       
   841 				iSuffix.Zero();
       
   842 				return EFalse;
       
   843 				}
       
   844 			else
       
   845 			if (periodIdx)
       
   846 				{
       
   847 				// If there are KInvNameAndMinSuffixLength chars after the period
       
   848 				// simply replace them.
       
   849 				TInt right = iOriginalBaseLength-periodIdx-1;
       
   850 				iSuffix = iFileName->Right(right);
       
   851 				iOriginalBaseLength -= right;
       
   852 				iFileName->SetLength(iOriginalBaseLength);					
       
   853 				}
       
   854 			else
       
   855 				{
       
   856 				// Make the suffix start from KInvNameAndMinSuffixLength 
       
   857 				// from the right
       
   858 				TInt right = KInvNameAndMinSuffixLength;
       
   859 				iSuffix = iFileName->Right(right);
       
   860 				iOriginalBaseLength -= right;
       
   861 				iFileName->SetLength(iOriginalBaseLength);					
       
   862 				}
       
   863 			}
       
   864 		}
       
   865 	else
       
   866 		{
       
   867 		// bad or no suffix - treat the same
       
   868 		iSuffix.Zero();
       
   869 		return EFalse;
       
   870 		}
       
   871 
       
   872 	// For filenames with no drive letter prefix and also for filenames
       
   873 	// shorter than the drive letter length, i.e. with no drive
       
   874 	// information, insert it.
       
   875 	// Handles if the user simply enters the drive, e.g. "c:".
       
   876 	if (iOriginalBaseLength < KMaxDriveName || (*iFileName)[1] != ':')
       
   877 		{
       
   878 		// Set up the default if none supplied and make room in the filename 
       
   879         // array to contain a drive specification. Set initial drive letter to -1
       
   880         // so the iFileName is repaired before exited 
       
   881 		iInitialDriveLetter = -1;
       
   882 		iFileName->Insert(0, _L("_:")); 
       
   883 		iDrives.Append('Z');
       
   884 		}
       
   885 	else
       
   886 		{
       
   887 	   // Use the drive supplied inthe aName to NearestLanguageFile()
       
   888 		iInitialDriveLetter = (*iFileName)[0];
       
   889 		iDrives.Append(iInitialDriveLetter);
       
   890 		}
       
   891 	
       
   892 	iBaseLength = iFileName->Length();
       
   893 	
       
   894 	return ETrue;
       
   895 	}
       
   896 
       
   897 
       
   898 TLanguage TNearestLanguageFileFinder::Language()
       
   899 	{
       
   900 	return iLanguage;
       
   901 	}
       
   902 
       
   903 TNearestLanguageFileFinder::TNearestLanguageFileFinder(
       
   904 	const RFs& aFs)
       
   905 	: iFs(aFs), iFileName(0), iLanguage(ELangNone)
       
   906 	{
       
   907 	}
       
   908 
       
   909 void TNearestLanguageFileFinder::RepairFileName()
       
   910 	{
       
   911 	ASSERT(iFileName);
       
   912 	iFileName->SetLength(iBaseLength);
       
   913 	if (iInitialDriveLetter == -1)
       
   914 		iFileName->Delete(0, 2);
       
   915 	else
       
   916 		(*iFileName)[0] = static_cast<TText>(iInitialDriveLetter);
       
   917 	iFileName->SetLength(iOriginalBaseLength);
       
   918 	iFileName->Append(iSuffix);
       
   919 	}
       
   920 
       
   921 
       
   922 /**
       
   923 Add the custom resource drive to the start of the iDrives string.
       
   924 
       
   925 The custom resource drive is a preset writeable drive on which customised 
       
   926 resource files may be present. This drive takes priority over the other 
       
   927 drives when searching for language files.
       
   928 
       
   929 @return KErrNone if iDrives string was successfully modified; KErrAlreadyExists 
       
   930 if the drive is already present in the string; otherwise one of 
       
   931 the other system-wide error codes (iDrives will be unmodified). 
       
   932 */
       
   933 TInt TNearestLanguageFileFinder::AddCustomResourceDrive()
       
   934 	{
       
   935 	TInt drive = GetCustomResourceDriveNumber();
       
   936 	if (drive<0)
       
   937 		return drive;
       
   938 	
       
   939 	// if drive not already in drive list
       
   940 	if (iDrives.LocateF('A' + drive) < 0)
       
   941 		{
       
   942 		// add it
       
   943 		_LIT(KDrivePlaceholder, "_");
       
   944 		iDrives.Insert(0, KDrivePlaceholder);
       
   945 		iDrives[0] = 'A' + drive;
       
   946 		return KErrNone;
       
   947 		}
       
   948 	else
       
   949 		return KErrAlreadyExists;
       
   950 	}
       
   951 
       
   952 
       
   953 void TNearestLanguageFileFinder::AddAllDrives()
       
   954 	{
       
   955 	ASSERT(iDrives.Length() < 2);
       
   956 	if (iDrives.Length() == 0)
       
   957 		{
       
   958 		iDrives = KAllDrives;
       
   959 		return;
       
   960 		}
       
   961 	TInt pos = KAllDrives().LocateF(iDrives[0]);
       
   962 	if (pos < 0)
       
   963 		{
       
   964 		iDrives = KAllDrives;
       
   965 		return;
       
   966 		}
       
   967 	iDrives.Append(KAllDrives().Left(pos));
       
   968 	iDrives.Append(KAllDrives().Mid(pos + 1));
       
   969 	}
       
   970 
       
   971 
       
   972 /**
       
   973 Get the value of the custom resource drive.
       
   974 
       
   975 The custom resource drive is a preset writeable drive on which customised language resource 
       
   976 files can reside. The drive number is accessed via the HAL attribute ECustomResourceDrive. 
       
   977 It is then returned if it has been defined as a valid drive no.
       
   978 Otherwise for backward compatibility reasons an attempt is then made to access the system 
       
   979 drive HAL attribute instead. This drive number is returned if it has been defined as a valid 
       
   980 drive number.  
       
   981 Otherwise if neither a valid ECustomResourceDrive or ESystemDrive exists then KErrNotFound 
       
   982 is returned.
       
   983  
       
   984 Note that the ESystemDrive HAL attribute has been deprecated. It is accessed here to cater 
       
   985 for existing implementations which still expect it to be used.
       
   986  
       
   987 @return The drive number (corresponding to a TDriveNumber value) if successful; 
       
   988 KErrNotFound if neither a valid ECustomResourceDrive or a valid ESystemDrive HAL attribute 
       
   989 is defined;  
       
   990  
       
   991 @see HAL::ECustomResourceDrive
       
   992 @see HAL::ESystemDrive
       
   993 */
       
   994 TInt TNearestLanguageFileFinder::GetCustomResourceDriveNumber() const
       
   995 	{
       
   996 	TInt drive = KErrNotFound;
       
   997 	
       
   998 	// access custom resource drive attribute  
       
   999 	if (HAL::Get(HAL::ECustomResourceDrive, drive) == KErrNone)
       
  1000 		{
       
  1001 		// check that drive is valid
       
  1002 		if (drive>=EDriveA && drive<=EDriveZ)
       
  1003 			return drive;	 
       
  1004 		}
       
  1005 		    		    
       
  1006 	// access system drive attribute  
       
  1007 	// (Note that ESystemDrive is deprecated. It is checked here 
       
  1008 	// solely for backward compatibility reasons.)		
       
  1009 	if (HAL::Get(HAL::ESystemDrive, drive) == KErrNone)
       
  1010 		{
       
  1011 		// check that drive is valid
       
  1012 		if (drive>=EDriveA && drive<=EDriveZ)
       
  1013 				return drive;
       
  1014 		}		
       
  1015  
       
  1016 	return KErrNotFound;
       
  1017 	}
       
  1018 
       
  1019 
       
  1020 
       
  1021 /** Get the value of the system drive.
       
  1022 
       
  1023 The system drive can be set to one of the built-in read/write drives. Which 
       
  1024 drive is used is hardware-dependent. On some hardware, there may not be a 
       
  1025 system drive. The system drive is used as the drive on which localisable files 
       
  1026 are searched for. This enables a phone to be localised dynamically, using 
       
  1027 files not in the ROM.
       
  1028 
       
  1029 @param aDriveNumber On return, contains the drive number of the system drive.
       
  1030 @return KErrNone is always returned.
       
  1031 
       
  1032 @deprecated This method has been replaced by (and now internally calls) 
       
  1033 RFs:GetSystemDrive, which always returns a valid drive number.
       
  1034 
       
  1035 @see BaflUtils::NearestLanguageFile
       
  1036 @see RFs::GetSystemDrive
       
  1037 */
       
  1038 EXPORT_C TInt BaflUtils::GetSystemDrive(TDriveNumber& aDriveNumber)
       
  1039 	{
       
  1040 	aDriveNumber = RFs::GetSystemDrive();
       
  1041 	return KErrNone;
       
  1042 	}
       
  1043 
       
  1044 
       
  1045 /** Set most appropriate extension language code for filename and set corresponding language.
       
  1046 
       
  1047 Symbian uses numeric values to identify natural languages as specified by the TLanguage enumeration
       
  1048 defined in e32const.h. These values are used at the end of filename extensions to identify the
       
  1049 languages pertaining to files which have language specific variants such as resource files.
       
  1050 For instance filename.r01 and filename.r02 would be the English and French versions of the
       
  1051 resource file filename.rsc. Language codes can be between 2 to 5 digits in length.
       
  1052 
       
  1053 Starting from Symbian OS v7.0 this function constructs and uses a language downgrade path which 
       
  1054 consists of up to sixteen TLanguage values the first of which is the ideal language followed by 
       
  1055 the language of the current locale. Up to the next three can be customised using 
       
  1056 TLocale::SetLanguageDowngrade(). The rest of the language downgrade path is based on a 
       
  1057 table of language near equivalence which is internal to Symbian.
       
  1058 
       
  1059 This function searches the custom resource drive (if set, retrieved from HAL)
       
  1060 and then searches the optional drive specified in aName or 'Z:' if none is 
       
  1061 specified in aName. The custom resource drive is retrieved from the HAL 
       
  1062 attribute ECustomResourceDrive if set, if not set it will retrieve the legacy 
       
  1063 value set in the legacy HAL attribute ESystemDrive. No custom resource drive 
       
  1064 is searched if neither are set.  
       
  1065 Note - setting the custom resource drive will reduce the performance of this 
       
  1066 routine which will adversely affect device performance e.g. at boot up.
       
  1067 On NAND Flash based devices use of a composite Z: drive file system made up of multiple 
       
  1068 ROM images is the preferred mechanism for customising language resources on devices in 
       
  1069 Symbian OS 9.2 onwards, see Developer Library » Base Porting Guide » Porting: background 
       
  1070 information » NAND flash » NAND Flash image format. Thus use of the custom resource drive 
       
  1071 HAL attribute is effectively obsolete.
       
  1072   
       
  1073 The last two characters of aName are removed along with any digits which appear before them.
       
  1074 Then language codes specified in the constructed language downgrade path are appended in turn to 
       
  1075 aName as a match is searched for in the file system. In case no match is found using the 
       
  1076 constructed language downgradepath then files in the specified directory are searched for a 
       
  1077 suitable extension with preference given to the one specified if present. In cases where a 
       
  1078 match takes place the aName and aLanguage arguments are updated otherwise aName is left 
       
  1079 unchanged and aLanguage is set to ELangNone.
       
  1080 
       
  1081 Here are some examples of correct and incorrect function usage with different aName inputs, 
       
  1082 file system state and downgrade paths as follows: 
       
  1083 
       
  1084 @code
       
  1085 Following files exist:
       
  1086 C:\\abc.rsc  - Language Neutral resource file.
       
  1087 C:\\abc.r01  - Resource file for the English language.
       
  1088 C:\\abc.r10  - Resource file for the American-English language.
       
  1089 C:\\abc.r160 - Resource file for the English as appropriate in Japan.
       
  1090 
       
  1091 Constructed Downgrade Language Path cases:
       
  1092 - Case 1. (ELangAmerican -> ELangEnglish -> ELangNone).
       
  1093 - Case 2. (ELangEnglish_Japan -> ELangEnglish -> ELangNone).
       
  1094 - Case 3. Same as case 1, However "C:\\abc.r10" is deleted prior to the function call.
       
  1095 - Case 4. Same as case 1, However both "C:\\abc.r01" and "C:\\abc.r10" are deleted prior to the function call.
       
  1096 @endcode
       
  1097 
       
  1098 @code
       
  1099 Input aName . . . . Output aName. . . aLanguage . . . . . Description
       
  1100 --------------------------------------------------------------------------------------------------------------------
       
  1101 "C:\\abc.rsc" . . . "C:\\abc.r10" . . ELangAmerican . . . Match on first language (Case 1)
       
  1102 "C:\\abc.r10" . . . "C:\\abc.r10" . . ELangAmerican . . . Match, However it's not the intended use of 
       
  1103 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . the function (Case 1)
       
  1104 "C:\\abc.r" . . . . "C:\\abc.r" . . . ELangNone . . . . . The no. of characters in the suffix is less than 
       
  1105 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . KInvNameAndMinSuffixLength(2)(Case 1)
       
  1106 "C:\\abc.". . . . . "C:\\abc.". . . . ELangNone . . . . . Invalid Suffix: The filename ends with a period(Case 1)
       
  1107 "C:\\abc.r123456" . "C:\\abc.r123456" ELangNone . . . . . Invalid Suffix: The no. of digits in the suffix is greater 
       
  1108 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . than KMaxSuffixLength(5) (Case 1)
       
  1109 "C:\\abc.10". . . . "C:\\abc.10 . . . ELangNone . . . . . Invalid Suffix: There's no proceeding alphabetical 
       
  1110 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . characters in the suffix (Case 1)
       
  1111 "\\abc.rsc" . . . . "\\abc.rsc" . . . ELangNone . . . . . No drive so Z: search, no match (Case 1)
       
  1112 "C:\\abc.rsc" . . . "C:\\abc.r160". . ELangEnglish_Japan. Match for language file 3 digits long (Case 2)
       
  1113 "C:\\abc.rsc" . . . "C:\\abc.r01" . . ELangEnglish. . . . Match on second language (Case 3)
       
  1114 "C:\\abc.rsc" . . . "C:\\abc.rsc" . . ELangNone . . . . . No corresponding langauge file match found (Case 4)
       
  1115 ---------------------------------------------------------------------------------------------------------------------
       
  1116 @endcode
       
  1117 
       
  1118 @param aFs File server session.
       
  1119 @param aName Optional drive specification, followed by optional path name,
       
  1120 followed by basename for filename, followed by period and extension.
       
  1121 On return, in case of a match, this is replaced by the language-specific version
       
  1122 which consists of the last two characters of the extension plus any preceding
       
  1123 numeric characters being replaced by the language code. Remains unchanged when there's no match 
       
  1124 @param aLanguage On return, in case of a match, this is replaced by the corresponding language.
       
  1125 In case of no match it's set to ELangNone.
       
  1126 @see TLanguage
       
  1127 @see BaflUtils::GetDowngradePathL
       
  1128 @see TLocale::SetLanguageDowngrade
       
  1129 */
       
  1130 EXPORT_C void BaflUtils::NearestLanguageFile(const RFs& aFs,TFileName& aName, TLanguage& aLanguage)
       
  1131 	{
       
  1132 #if defined(DO_PROFILING)
       
  1133 	RDebug::ProfileReset(FIRST_PROFILE_INDEX, PROFILE_COUNT);
       
  1134 	RDebug::ProfileStart(PROFILE_INDEX_1);
       
  1135 #endif
       
  1136 	TNearestLanguageFileFinder finder(aFs);
       
  1137 	TBool goodSuffix=finder.SetFileName(aName);
       
  1138 	
       
  1139 	// Only continue if the suffix is good.
       
  1140 	if(goodSuffix)
       
  1141 		{
       
  1142 		// add preset customised resource drive to drive list  
       
  1143 		// Note that errors returned from AddCustomResourceDrive are ignored. This is because if 
       
  1144 		// a custom resource drive has not been found we still want to continue on with searching 
       
  1145 		// other drives according to our algorithm
       
  1146 		finder.AddCustomResourceDrive();
       
  1147 		
       
  1148 		TLocale locale;
       
  1149 		TLanguage idealLanguage;
       
  1150 		idealLanguage = IdealLanguage();
       
  1151 		MakeLanguageDowngradePath(finder.iPath, User::Language(), idealLanguage, locale);
       
  1152 		if (!finder.FindLanguageAndDrive()
       
  1153 			&& KErrNone != finder.FindFirstLanguageFileAndDrive())
       
  1154 			finder.RepairFileName();
       
  1155 		aLanguage = finder.Language();
       
  1156 		}
       
  1157 		
       
  1158 #if defined(DO_PROFILING)
       
  1159 	RDebug::ProfileEnd(PROFILE_INDEX_1);
       
  1160 	TProfile profile[PROFILE_COUNT];
       
  1161 	RDebug::ProfileResult(&profile[0], FIRST_PROFILE_INDEX, PROFILE_COUNT);
       
  1162 	if(goodSuffix)
       
  1163 		{
       
  1164 		RDebug::Print(_L("BaflUtils::NearestLanguageFile profile info: %d.%03ds"), profile[PROFILE_INDEX_1-FIRST_PROFILE_INDEX].iTime/1000000, profile[PROFILE_INDEX_1-FIRST_PROFILE_INDEX].iTime%1000000);
       
  1165 		}
       
  1166 	else
       
  1167 		{
       
  1168 		RDebug::Print(_L("BaflUtils::NearestLanguageFile (bad suffix ) profile info: %d.%03ds"), profile[PROFILE_INDEX_1-FIRST_PROFILE_INDEX].iTime/1000000, profile[PROFILE_INDEX_1-FIRST_PROFILE_INDEX].iTime%1000000);
       
  1169 		}
       
  1170 #endif
       
  1171 	}
       
  1172 	
       
  1173 /** Searches for the file with the correct language extension for the language 
       
  1174 of the current locale, or failing this, the best matching file.
       
  1175 
       
  1176 @param aFs File server session.
       
  1177 @param aName File name as it would be without a language-specific extension. 
       
  1178 On return, this is changed to the language-specific version. If no such file 
       
  1179 is found, the name is unchanged.
       
  1180 @see BaflUtils::NearestLanguageFile(const RFs& aFs,TFileName& aName, TLanguage& aLanguage) */
       
  1181 EXPORT_C void BaflUtils::NearestLanguageFile(const RFs& aFs,TFileName& aName)
       
  1182 	{
       
  1183 	TLanguage language;
       
  1184 	
       
  1185 	NearestLanguageFile( aFs, aName, language);
       
  1186 	
       
  1187 	(void)language;
       
  1188 	}
       
  1189 
       
  1190 /** Set the ideal language for the thread. 
       
  1191 This interface is intended for the use of UIKON only.
       
  1192 
       
  1193 @param aLanguage Ideal language.
       
  1194 @return KErrNone, if successful; KErrNoMemory if there is not enough memory @see TLanguage
       
  1195 @see BaflUtils::NearestLanguageFile() 
       
  1196 @internalAll */
       
  1197 EXPORT_C TInt BaflUtils::SetIdealLanguage(TLanguage aLanguage)
       
  1198 	{
       
  1199 	TLanguage* langPtr=(TLanguage*)Dll::Tls();
       
  1200 	if( langPtr==NULL)
       
  1201 		{
       
  1202 		langPtr=(TLanguage*)User::Alloc(sizeof(TLanguage));
       
  1203 		
       
  1204 		if(!langPtr) 
       
  1205 			return(KErrNoMemory);
       
  1206 		
       
  1207 		TInt ret=Dll::SetTls(langPtr);
       
  1208 		
       
  1209 		if(ret!=KErrNone)
       
  1210 			return(ret);
       
  1211 		}
       
  1212 	*langPtr=aLanguage;
       
  1213 	return(KErrNone);
       
  1214 	}
       
  1215 	
       
  1216 /** Get the ideal language of the thread. 
       
  1217 This interface is intended for the use of UIKON only.
       
  1218 
       
  1219 @return Ideal language if set, ELangNone if not set
       
  1220 @see BaflUtils::NearestLanguageFile() 
       
  1221 @internalAll */
       
  1222 EXPORT_C TLanguage BaflUtils::IdealLanguage()
       
  1223 	{
       
  1224 	TLanguage* langPtr=(TLanguage*)Dll::Tls();
       
  1225 	
       
  1226 	if( langPtr==NULL)
       
  1227 		{
       
  1228 		return(ELangNone);
       
  1229 		}
       
  1230 
       
  1231 	return(*langPtr);
       
  1232 	}
       
  1233 	
       
  1234 EXPORT_C void BaflUtils::ReleaseIdealLanguage()
       
  1235 /** Releases the ideal language store if it has been allocated. 
       
  1236 This interface is intended for the use of UIKON only.
       
  1237 
       
  1238 @internalAll */
       
  1239 	{
       
  1240 	TLanguage* aLanguage=(TLanguage*)Dll::Tls();
       
  1241 	if( aLanguage==NULL)
       
  1242 		return;
       
  1243 	
       
  1244 	delete aLanguage;
       
  1245 	Dll::FreeTls();
       
  1246 	}
       
  1247 
       
  1248 EXPORT_C TInt BaflUtils::IsFolder(const RFs& aFs, const TDesC& aFullName, TBool& aIsFolder)
       
  1249 /** Checks if the specified item is a folder.
       
  1250 
       
  1251 @param aFs File server session
       
  1252 @param aFullName Name to check
       
  1253 @param aIsFolder ETrue if aFullName is a folder, otherwise EFalse
       
  1254 @return KErrNone if successful, otherwise another of the system-wide error 
       
  1255 codes */
       
  1256 	{
       
  1257 	TParsePtrC parse(aFullName);
       
  1258 	if ((parse.DriveAndPath().Length() == KDriveAndPathLength) && (aFullName.Length() == KDriveAndPathLength))	
       
  1259 		{
       
  1260 		aIsFolder = ETrue;
       
  1261 		return(KErrNone);
       
  1262 		}
       
  1263 	TEntry entry;
       
  1264 	TInt retcode = aFs.Entry(aFullName, entry);
       
  1265 	if (retcode == KErrNone)
       
  1266 		aIsFolder = ((entry.iAtt & KEntryAttDir)==KEntryAttDir);
       
  1267 
       
  1268 	return(retcode);
       
  1269 	}
       
  1270 
       
  1271 
       
  1272 EXPORT_C TBool BaflUtils::FolderExists(RFs& aFs, const TDesC& aFolderName)
       
  1273 /** Tests whether a folder exists.
       
  1274 
       
  1275 The folder is specified in a path. The path can omit the drive letter, in 
       
  1276 which case the drive letter is taken from the session path.
       
  1277 
       
  1278 If the path is badly formed, for instance if it contains illegal characters, 
       
  1279 or any directory name consists of a single or double dot, or any directory 
       
  1280 name includes wildcard characters, the function returns EFalse.
       
  1281 
       
  1282 If a filename is included in the path, it is ignored (the existence 
       
  1283 of the file will not be checked).  However if included, it must not
       
  1284 be badly formed - this will cause the function to return EFalse.  
       
  1285 If no filename is specified, the path should end in a backslash.
       
  1286 
       
  1287 Examples of valid paths (returning ETrue):
       
  1288 C:\; \; C:\Readme.txt; C:\system\data\; \system\data\Anyfile.dat
       
  1289 
       
  1290 Examples of invalid paths (returning EFalse):
       
  1291 C:\FolderDoesntExist\; ..\system\; C:\Wild*card\; C:\system\data\Bad>File.txt
       
  1292 
       
  1293 @param aFs A connected session with the file server.
       
  1294 @param aFolderName A path specifying the folder to test for.
       
  1295 @return ETrue if the folder specified in aFolderName exists, EFalse if not. 
       
  1296 EFalse is also returned if the specified path is badly formed. */
       
  1297 	{	
       
  1298 	if (aFolderName.Length()==0)
       
  1299 		{return EFalse;}
       
  1300 	
       
  1301 	TParse parse;
       
  1302 		 	
       
  1303  	TInt retcode = parse.SetNoWild(aFolderName, NULL, NULL);
       
  1304  	
       
  1305  	if (retcode != KErrNone)
       
  1306  		{return EFalse;}
       
  1307  			
       
  1308  	if (parse.NameOrExtPresent())
       
  1309  		if (!aFs.IsValidName(aFolderName))
       
  1310  			{return EFalse;}
       
  1311  	
       
  1312  	TPtrC dirName = parse.DriveAndPath();
       
  1313  	RDir dir;
       
  1314     retcode = dir.Open(aFs,dirName,0);
       
  1315  	if (retcode == KErrNone)
       
  1316  		{dir.Close();}
       
  1317  	return (retcode == KErrNone);
       
  1318 	}
       
  1319 
       
  1320 
       
  1321 EXPORT_C TFileName BaflUtils::FolderNameFromFullName(const TDesC& aFullName) 
       
  1322 /** Gets the folder name from a path.
       
  1323 
       
  1324 A valid full name should have a drive associated with it
       
  1325 e.g ("a:\\" - "z:\\")("a:" - "z:")("c:\\system\data\file.txt")
       
  1326 Invalid entry will have no drive and cause a panic EBafPanicBadOpenArg
       
  1327 For example, if the path is "c:\documents\word\mydoc1", then "word" is returned.
       
  1328 							"c:"						then "c:" is returned
       
  1329 							"c:\\"						then "c:\" is returned
       
  1330 							"c:\\mydoc1.txt				then "c:\" is returned
       
  1331 
       
  1332 @param aFullName A path.
       
  1333 @return The folder name. */
       
  1334 	{
       
  1335 	TParsePtrC parse(aFullName);
       
  1336 	
       
  1337 	__ASSERT_ALWAYS(parse.DrivePresent(),Panic(EBafPanicBadOpenArg));
       
  1338 	
       
  1339 	TFileName folderName = parse.Path();
       
  1340 	//If the path name has no associated path(e.g "c:") or path='\'(e.g "c:\\", "c:\\file.txt")
       
  1341 	//then the folder name is just equal to drivename
       
  1342 	
       
  1343 	TBuf<1> pathSeparator;
       
  1344 	pathSeparator.Append(KPathDelimiter);
       
  1345 
       
  1346 	if (folderName.Length()==0 || folderName==pathSeparator)
       
  1347 		return (parse.DriveAndPath());
       
  1348 	//else just get the foldername
       
  1349 	TInt len = folderName.Length();
       
  1350 	TInt pos = --len;
       
  1351 	while (--pos)
       
  1352 		if (folderName.Mid(pos, 1)==pathSeparator)
       
  1353 			break;
       
  1354 	folderName.Delete(len, 1);
       
  1355 	folderName.Delete(0, pos+1);
       
  1356 	return(folderName);
       
  1357 	}
       
  1358 
       
  1359 
       
  1360 EXPORT_C TFileName BaflUtils::DriveAndPathFromFullName(const TDesC& aFullName) 
       
  1361 /** Gets the drive letter and path from a file name. 
       
  1362 
       
  1363 This is in the form: drive-letter:\\path\\. The drive letter is folded using 
       
  1364 class TCharF. 
       
  1365 
       
  1366 @param aFullName File name
       
  1367 @return The drive and path */
       
  1368 	{
       
  1369 	TParsePtrC parse(aFullName);
       
  1370 	return (parse.DriveAndPath());
       
  1371 	}
       
  1372 
       
  1373 
       
  1374 EXPORT_C TFileName BaflUtils::RootFolderPath(const TBuf<1> aDriveLetter)
       
  1375 /** Gets the root folder for the specified drive.
       
  1376 
       
  1377 If aDriveLetter is an alphabet(lowercase or uppercase) then it will return
       
  1378 the TFileName which is simply the drive letter plus ":\"
       
  1379 If this is not the case, the function will panic with panic code EBafPanicBadOpenArg
       
  1380 
       
  1381 @param aDriveLetter Drive letter
       
  1382 @return Root folder */
       
  1383 	{
       
  1384 	TChar driveLetter(aDriveLetter[0]);
       
  1385 	driveLetter.LowerCase();
       
  1386 	TInt aDriveNumber=driveLetter-TChar('a');
       
  1387 	__ASSERT_ALWAYS(aDriveNumber>= EDriveA && aDriveNumber <= EDriveZ,Panic(EBafPanicBadOpenArg));
       
  1388 	
       
  1389 	TFileName rootFolderPath = aDriveLetter;
       
  1390 	rootFolderPath.Append(_L(":\\"));
       
  1391 	return rootFolderPath;
       
  1392 	}
       
  1393 
       
  1394 
       
  1395 EXPORT_C void BaflUtils::AbbreviateFileName(const TFileName& aOriginalFileName, TDes& aAbbreviatedFileName)
       
  1396 /** Abbreviates a file name.
       
  1397 
       
  1398 If aOriginalFileName is less than the maximum length of aAbbreviatedFileName, 
       
  1399 then the name is simply copied to aAbbreviatedFileName.
       
  1400 
       
  1401 If this is not so, then the left-most characters of aOriginalFileName are 
       
  1402 copied to aAbbreviatedFileName, up to aAbbreviatedFileName's maximum length-1. 
       
  1403 aAbbreviatedFileName's first character is set to be an ellipsis.
       
  1404 
       
  1405 @param aOriginalFileName Original file name
       
  1406 @param aAbbreviatedFileName On return, abbreviated file name */
       
  1407 	{
       
  1408 	TInt maxWidthInChars = aAbbreviatedFileName.MaxLength();
       
  1409 	if (aOriginalFileName.Length() <= maxWidthInChars)
       
  1410 		{
       
  1411 		aAbbreviatedFileName = aOriginalFileName;
       
  1412 		return;
       
  1413 		}
       
  1414 	TChar ellipsis(0x2026);
       
  1415 	--maxWidthInChars;  // since the ellipsis will be the first char in aAbbreviatedFileName
       
  1416 	aAbbreviatedFileName.Zero();
       
  1417 	aAbbreviatedFileName.Append(ellipsis);
       
  1418 	aAbbreviatedFileName.Append(aOriginalFileName.Mid((aOriginalFileName.Length() - 1) - maxWidthInChars + 1, maxWidthInChars));
       
  1419 	}
       
  1420 
       
  1421 
       
  1422 EXPORT_C TBool BaflUtils::UidTypeMatches(const TUidType& aFileUid, const TUidType& aMatchUid)
       
  1423 /** Tests whether two UID types match.
       
  1424 
       
  1425 A match is made if each UID in aMatchUid is either identical to the corresponding 
       
  1426 one in aFileUid, or is KNullUid.
       
  1427 
       
  1428 @param aFileUid The UID type to match
       
  1429 @param aMatchUid The UID type to match against
       
  1430 @return ETrue if the UIDs match, otherwise EFalse */
       
  1431 	{
       
  1432 	for (TInt i=0; i<KMaxCheckedUid; i++)
       
  1433 		{
       
  1434 		if (aMatchUid[i] == KNullUid)
       
  1435 			continue;
       
  1436 		if (aMatchUid[i] != aFileUid[i])
       
  1437 			return(EFalse);
       
  1438 		}
       
  1439 	return(ETrue);
       
  1440 	}
       
  1441 
       
  1442 
       
  1443 EXPORT_C TInt BaflUtils::Parse(const TDesC& aName)
       
  1444 /** Checks if a specified file name can be parsed.
       
  1445 
       
  1446 @param aName Name to parse
       
  1447 @return KErrNone if successful, otherwise another of the system-wide error 
       
  1448 codes */
       
  1449 	{ // keeps a TParse on the stack for the minimum time possible
       
  1450 	TParse parse;
       
  1451 	return parse.Set(aName,NULL,NULL);
       
  1452 	}
       
  1453 
       
  1454 
       
  1455 EXPORT_C TInt BaflUtils::ValidateFolderNameTypedByUserL(const RFs& aFs, const TDesC& aFolderNameTypedByUser, const TDesC& aCurrentPath, TFileName& aNewFolderFullName)
       
  1456 /** Checks if a folder name (without drive or path) is valid and returns the full 
       
  1457 name of the folder.
       
  1458 
       
  1459 @param aFs File server session
       
  1460 @param aFolderNameTypedByUser Folder name to check
       
  1461 @param aCurrentPath Path to which to add the folder
       
  1462 @param aNewFolderFullName aFolderNameTypedByUser appended to aCurrentPath
       
  1463 @return KErrNone if successful, otherwise another of the system-wide error 
       
  1464 codes */
       
  1465 	{
       
  1466 	if (aFolderNameTypedByUser.Length() == 0)
       
  1467 		return KErrArgument;	// R_EIK_TBUF_NO_FOLDERNAME_SPECIFIED;
       
  1468 
       
  1469 	TParse* targetParse = new(ELeave) TParse;
       
  1470 	CleanupStack::PushL(targetParse);
       
  1471 
       
  1472 	TInt retcode = targetParse->Set(aFolderNameTypedByUser, NULL, NULL);
       
  1473 	User::LeaveIfError(retcode);
       
  1474 	if (targetParse->DrivePresent() || targetParse->PathPresent())
       
  1475 		{
       
  1476 		 CleanupStack::PopAndDestroy();
       
  1477 		 return KErrBadName;	// R_EIK_TBUF_INVALID_FOLDER_NAME;
       
  1478 		}
       
  1479 
       
  1480 	if (!(aFs.IsValidName(aFolderNameTypedByUser)))
       
  1481 		{
       
  1482 		 CleanupStack::PopAndDestroy();
       
  1483 		 return KErrBadName;	// R_EIK_TBUF_INVALID_FOLDER_NAME;
       
  1484 		}
       
  1485 		 
       
  1486 
       
  1487 	if ((aCurrentPath.Length() + aFolderNameTypedByUser.Length() + 1) > KMaxFileName)
       
  1488 		{
       
  1489 		 CleanupStack::PopAndDestroy();
       
  1490 		 return KErrTooBig;		//R_EIK_TBUF_FOLDERNAME_TOO_LONG;
       
  1491 		}
       
  1492 		 
       
  1493 
       
  1494 	//TFileName newFolderFullName = aCurrentPath;
       
  1495 	aNewFolderFullName = aCurrentPath;
       
  1496 	if ((aNewFolderFullName.Length() + aFolderNameTypedByUser.Length() + 1) <= KMaxFileName)
       
  1497 		{
       
  1498 		aNewFolderFullName.Append(aFolderNameTypedByUser);
       
  1499 		aNewFolderFullName.Append(KPathDelimiter);
       
  1500 		}
       
  1501 	else
       
  1502 		{
       
  1503 		CleanupStack::PopAndDestroy();
       
  1504 		return KErrOverflow;
       
  1505 		}
       
  1506 
       
  1507 	retcode = targetParse->Set(aNewFolderFullName, NULL, NULL);
       
  1508 	if (retcode != KErrNone)
       
  1509 		{
       
  1510 		CleanupStack::PopAndDestroy();
       
  1511 		return KErrBadName;	// R_EIK_TBUF_INVALID_FOLDER_NAME;
       
  1512 		}
       
  1513 	
       
  1514 	CleanupStack::PopAndDestroy();
       
  1515 
       
  1516 	return(KErrNone);
       
  1517 	}
       
  1518 
       
  1519 void BaflUtils::DoCopyFileL(RFs& aFs, const TDesC& aSourceFullName, const TDesC& aTargetFullName, TUint aSwitch)
       
  1520 	{
       
  1521 	CFileMan* fileMan=CFileMan::NewL(aFs);
       
  1522 	CleanupStack::PushL(fileMan);
       
  1523 	User::LeaveIfError(fileMan->Copy(aSourceFullName,aTargetFullName,aSwitch));
       
  1524 	CleanupStack::PopAndDestroy(); // fileMan
       
  1525 	}
       
  1526 
       
  1527 
       
  1528 EXPORT_C TInt BaflUtils::CopyFile(RFs& aFs, const TDesC& aSourceFullName, const TDesC& aTargetFullName, TUint aSwitch)
       
  1529 /** Copies one or more files.
       
  1530 
       
  1531 For more details, 
       
  1532 @see CFileMan::Copy()
       
  1533 @since     5.1
       
  1534 @param     aFs File server session
       
  1535 @param     aSourceFullName Path indicating the file(s) to be copied. Any path
       
  1536 components that are not specified here will be taken from the session path.
       
  1537 @param     aTargetFullName Path indicating the directory into which the file(s)
       
  1538 are to be copied
       
  1539 @param     aSwitch=CFileMan::EOverWrite Set this to zero for no overwriting and 
       
  1540 no recursion; CFileMan::EOverWrite to overwrite files with the same name; or 
       
  1541 CFileMan::ERecurse for recursion.
       
  1542 @return   KErrNone if successful, otherwise another of the system-wide error 
       
  1543 codes.*/
       
  1544 	{
       
  1545 	TRAPD(err,DoCopyFileL(aFs,aSourceFullName,aTargetFullName,aSwitch));
       
  1546 	return err;
       
  1547 	}
       
  1548 
       
  1549 void BaflUtils::DoDeleteFileL(RFs& aFs, const TDesC& aSourceFullName, TUint aSwitch)
       
  1550 	{
       
  1551 	CFileMan* fileMan=CFileMan::NewL(aFs);
       
  1552 	CleanupStack::PushL(fileMan);
       
  1553 	User::LeaveIfError(fileMan->Delete(aSourceFullName,aSwitch));
       
  1554 	CleanupStack::PopAndDestroy(); // fileMan
       
  1555 	}
       
  1556 
       
  1557 
       
  1558 EXPORT_C TInt BaflUtils::DeleteFile(RFs& aFs, const TDesC& aSourceFullName, TUint aSwitch)
       
  1559 /** Deletes one or more files.
       
  1560 
       
  1561 For more details,
       
  1562 @see CFileMan::Delete().
       
  1563 @since 5.1
       
  1564 @param aFs File server session
       
  1565 @param aSourceFullName Path indicating the file(s) to be deleted. May either
       
  1566 be a full path, or relative to the session path. Use wildcards to specify 
       
  1567 more than one file.
       
  1568 @param aSwitch=0  Specify CFileMan::ERecurse for recursion,
       
  1569 zero for no recursion.
       
  1570 @return KErrNone if successful, otherwise another of the system-wide error 
       
  1571 codes. */	
       
  1572     {
       
  1573 	TRAPD(err,DoDeleteFileL(aFs,aSourceFullName,aSwitch));
       
  1574 	return err;
       
  1575 	}
       
  1576 
       
  1577 void BaflUtils::DoRenameFileL(RFs& aFs, const TDesC& aOldFullName, const TDesC& aNewFullName, TUint aSwitch)
       
  1578 	{
       
  1579 	CFileMan* fileMan=CFileMan::NewL(aFs);
       
  1580 	CleanupStack::PushL(fileMan);
       
  1581 	User::LeaveIfError(fileMan->Rename(aOldFullName,aNewFullName,aSwitch));
       
  1582 	CleanupStack::PopAndDestroy(); // fileMan
       
  1583 	}
       
  1584 
       
  1585 
       
  1586 EXPORT_C TInt BaflUtils::RenameFile(RFs& aFs, const TDesC& aOldFullName, const TDesC& aNewFullName, TUint aSwitch)
       
  1587 /**  Renames or moves one or more files or directories.
       
  1588 
       
  1589 It can be used to move one or more files by specifying different
       
  1590 destination and source directories.
       
  1591 For more details, 
       
  1592 @see CFileMan::Rename().
       
  1593 @since 5.1
       
  1594 @param aFs File server session
       
  1595 @param aOldFullName Path specifying the file(s) to be renamed.
       
  1596 @param aNewFullName Path specifying the new name for the files and/or the
       
  1597 new directory. Any directories specified in this path that do not exist will 
       
  1598 be created.
       
  1599 @param aSwitch=CFileMan::EOverWrite  Specify zero for no overwriting, or
       
  1600 CFileMan::EOverWrite to overwrite files with the same name. This 
       
  1601 function cannot operate recursively.
       
  1602 @return KErrNone if successful, otherwise another of the system-wide error 
       
  1603 codes. */	
       
  1604     {
       
  1605 	TRAPD(err,DoRenameFileL(aFs,aOldFullName,aNewFullName,aSwitch));
       
  1606 	return err;
       
  1607 	}
       
  1608 
       
  1609 
       
  1610 EXPORT_C TInt BaflUtils::CheckWhetherFullNameRefersToFolder(const TDesC& aFullName, TBool& aIsFolder)
       
  1611 /** Checks if a string is a valid folder name.
       
  1612 
       
  1613 @param aFullName String to check
       
  1614 @param aIsFolder ETrue if aFullName is a valid folder name, otherwise EFalse
       
  1615 @return KErrNone if successful, otherwise another of the system-wide error 
       
  1616 codes (probably because aFullName cannot be parsed). */
       
  1617 	{
       
  1618 	aIsFolder = EFalse;
       
  1619 	TInt retcode = BaflUtils::Parse(aFullName);
       
  1620 	if (retcode != KErrNone)
       
  1621 		return(retcode);
       
  1622 	TParsePtrC parse(aFullName);
       
  1623 	if (! parse.NameOrExtPresent())
       
  1624 		aIsFolder = ETrue;
       
  1625 	return(KErrNone);
       
  1626 	}
       
  1627 
       
  1628 EXPORT_C TInt BaflUtils::MostSignificantPartOfFullName(const TDesC& aFullName, TFileName& aMostSignificantPart)
       
  1629 /** Gets the folder name if the specified item is a valid folder name, otherwise 
       
  1630 gets the file name.
       
  1631 
       
  1632 @param aFullName Item to parse
       
  1633 @param aMostSignificantPart Folder or file name
       
  1634 @return KErrNone if successful, otherwise another of the system-wide error 
       
  1635 codes */
       
  1636 	{
       
  1637 	TBool entryIsAFolder;
       
  1638 	TInt retcode = CheckWhetherFullNameRefersToFolder(aFullName, entryIsAFolder);
       
  1639 	if (retcode != KErrNone)
       
  1640 		return(retcode);
       
  1641 	if (entryIsAFolder)
       
  1642 		{
       
  1643 		aMostSignificantPart = FolderNameFromFullName(aFullName);
       
  1644 		return (KErrNone);
       
  1645 		}
       
  1646 	// assume aFullName refers to a file
       
  1647 	TParsePtrC parse(aFullName);
       
  1648 	aMostSignificantPart = parse.NameAndExt();
       
  1649 	return(KErrNone);
       
  1650 	}
       
  1651 
       
  1652 EXPORT_C TInt BaflUtils::CheckFolder(RFs& aFs, const TDesC& aFolderName)
       
  1653 /** Checks that the specified folder can be opened.
       
  1654 
       
  1655 @param aFs File server session
       
  1656 @param aFolderName Folder to check
       
  1657 @return KErrNone if successful, otherwise another of the system-wide error 
       
  1658 codes */
       
  1659 	{
       
  1660     RDir dir;
       
  1661     TInt retcode = dir.Open(aFs, aFolderName, 0);
       
  1662 	if (retcode == KErrNone)
       
  1663 		dir.Close();
       
  1664 	return (retcode);
       
  1665 	}
       
  1666 
       
  1667 /**
       
  1668 Checks if the specified drive is read-only.
       
  1669 Checks that the KMediaAttWriteProtected and EMediaRom flags are both set.
       
  1670 
       
  1671 @param aFs File server session
       
  1672 @param aFullName File name, including drive
       
  1673 @param aIsReadOnly On return, ETrue if the drive is read-only, otherwise EFalse
       
  1674 @return KErrNone if successful, otherwise another of the system-wide error codes
       
  1675 @see BaflUtils::DriveIsReadOnlyInternal
       
  1676 */
       
  1677 EXPORT_C TInt BaflUtils::DiskIsReadOnly(RFs& aFs, const TDesC& aFullName, TBool& aIsReadOnly)
       
  1678 	{
       
  1679 	TInt retcode=BaflUtils::Parse(aFullName);
       
  1680 	if (retcode!=KErrNone)
       
  1681 		return retcode;
       
  1682 	TParsePtrC parse(aFullName);
       
  1683 	if (!parse.DrivePresent())
       
  1684 		return KErrBadName;
       
  1685 	TBuf<1> drive=parse.Drive().Left(1);
       
  1686 	TChar driveLetter=drive[0];
       
  1687 	TInt driveId=0;
       
  1688 	retcode=RFs::CharToDrive(driveLetter,driveId);
       
  1689 	if (retcode!=KErrNone)
       
  1690 		return retcode;
       
  1691 	TVolumeInfo volInfo;
       
  1692 	retcode=aFs.Volume(volInfo,driveId);
       
  1693 	if (retcode!=KErrNone)
       
  1694 		return retcode;
       
  1695 	aIsReadOnly=(volInfo.iDrive.iMediaAtt&KMediaAttWriteProtected || volInfo.iDrive.iType==EMediaRom);
       
  1696 	return KErrNone;
       
  1697 	}
       
  1698 
       
  1699 /** 
       
  1700 Checks if the specified drive is read-only and is an internal drive i.e. non-removable.
       
  1701 Checks that the KMediaAttWriteProtected and KDriveAttInternal flags are both set.
       
  1702 
       
  1703 @param aFs File server session
       
  1704 @param aFullName File name, including drive
       
  1705 @param aIsReadOnlyInternal On return, ETrue if the drive is read-only and internal, otherwise EFalse
       
  1706 @return KErrNone if successful, otherwise another of the system-wide errors codes 
       
  1707 */
       
  1708 EXPORT_C TInt BaflUtils::DriveIsReadOnlyInternal(RFs& aFs, const TDesC& aFullName, TBool& aIsReadOnlyInternal)
       
  1709 	{
       
  1710 	TInt retcode=BaflUtils::Parse(aFullName);
       
  1711 	if (retcode!=KErrNone)
       
  1712 		return retcode;
       
  1713 	TParsePtrC parse(aFullName);
       
  1714 	if (!parse.DrivePresent())
       
  1715 		return KErrBadName;
       
  1716 	TBuf<1> drive=parse.Drive().Left(1);
       
  1717 	TChar driveLetter=drive[0];
       
  1718 	TInt driveId=0;
       
  1719 	retcode=RFs::CharToDrive(driveLetter,driveId);
       
  1720 	if (retcode!=KErrNone)
       
  1721 		return retcode;
       
  1722 	TVolumeInfo volInfo;
       
  1723 	retcode=aFs.Volume(volInfo,driveId);
       
  1724 	if (retcode!=KErrNone)
       
  1725 		return retcode;
       
  1726 	aIsReadOnlyInternal=((volInfo.iDrive.iMediaAtt&KMediaAttWriteProtected)&&(volInfo.iDrive.iDriveAtt&KDriveAttInternal));
       
  1727 	return KErrNone;
       
  1728 	}
       
  1729 
       
  1730 EXPORT_C void BaflUtils::GetDiskListL(const RFs& aFs,CDesCArray& aArray)
       
  1731 /** Retrieves a list of all drives on the system.
       
  1732 
       
  1733 The file server is interrogated for a list of the drive letters for all available 
       
  1734 drives. 
       
  1735 
       
  1736 On emulator:
       
  1737 The removable media is represented by drive X: .
       
  1738 
       
  1739 On hardware:
       
  1740 The removable media is represented by drives D: E: F: and G: .
       
  1741 
       
  1742 @param aFs A connected session with the file server.
       
  1743 @param aArray On return, contains the drive letters that correspond to the 
       
  1744 available drives. The drive letters are uppercase and are in alphabetical 
       
  1745 order. */
       
  1746 	{ // static
       
  1747 	aArray.Reset();
       
  1748 	TDriveList driveList;
       
  1749 	User::LeaveIfError(aFs.DriveList(driveList));
       
  1750 	for (TInt ii=0;ii<KMaxDrives;ii++)
       
  1751 		{
       
  1752 		if (driveList[ii])
       
  1753 			{
       
  1754 			TChar drive;
       
  1755 			User::LeaveIfError(aFs.DriveToChar(ii,drive));
       
  1756 			drive.UpperCase();
       
  1757 			TBuf<1> buf;
       
  1758 			buf.Append(drive);
       
  1759 			aArray.AppendL(buf);
       
  1760 			}
       
  1761 		}
       
  1762 	}
       
  1763 
       
  1764 EXPORT_C void BaflUtils::UpdateDiskListL(const RFs& aFs,CDesCArray& aArray,TBool aIncludeRom,TDriveNumber aDriveNumber)
       
  1765 /** Retrieves a list of all drives present on the system.
       
  1766 
       
  1767 The file server is interrogated for a list of the drive letters for all available 
       
  1768 drives. The drive letter that corresponds to aDriveNumber is added to the 
       
  1769 list regardless of whether it is present, or is corrupt. Also, the C: drive 
       
  1770 is forced onto the list, even if corrupt or not present.
       
  1771 
       
  1772 On emulator:
       
  1773 The removable media is represented by drive X: and is forced onto the list 
       
  1774 unless removed (F5,F4).
       
  1775 
       
  1776 On hardware:
       
  1777 The removable media is represented by drives D: E: F: and G: and is forced 
       
  1778 onto the list regardless of whether it is present, or is corrupt.
       
  1779 
       
  1780 @param aFs A connected session with the file server.
       
  1781 @param aArray On return, contains the drive letters that correspond to the 
       
  1782 available drives. The drive letters are uppercase and are in alphabetical 
       
  1783 order.
       
  1784 @param aIncludeRom Specify ETrue if the ROM drive should be included in the 
       
  1785 list, EFalse if not.
       
  1786 @param aDriveNumber The drive to force into the list, e.g. the drive in the 
       
  1787 default path. */
       
  1788 	{ // static
       
  1789 	aArray.Reset();
       
  1790 	TDriveList driveList;
       
  1791 	User::LeaveIfError(aFs.DriveList(driveList));
       
  1792 	for (TInt ii=0;ii<KMaxDrives;ii++)
       
  1793 		{
       
  1794 		if (driveList[ii] || ii==aDriveNumber)
       
  1795 			{
       
  1796 			TVolumeInfo vInfo;
       
  1797 			const TInt err=aFs.Volume(vInfo,TDriveUnit(ii));
       
  1798 			if (err==KErrNone || err==KErrCorrupt || ii==aDriveNumber || BaflUtils::IsFirstDriveForSocket(TDriveUnit(ii)))
       
  1799 				{
       
  1800 				if (ii==EDriveZ && vInfo.iDrive.iDriveAtt&KDriveAttRom && !aIncludeRom)
       
  1801 					continue;
       
  1802 				TChar drive;
       
  1803 				User::LeaveIfError(aFs.DriveToChar(ii,drive));
       
  1804 				drive.UpperCase();
       
  1805 				TBuf<1> buf;
       
  1806 				buf.Append(drive);
       
  1807 				aArray.AppendL(buf);
       
  1808 				}
       
  1809 			}
       
  1810 		}
       
  1811 	}
       
  1812 
       
  1813 EXPORT_C TBool BaflUtils::IsFirstDriveForSocket(TDriveUnit aDriveUnit)
       
  1814 /** Tests whether the specified drive corresponds to the primary partition in a 
       
  1815 removable media slot.
       
  1816 
       
  1817 The function assumes that the D: drive corresponds to the primary partition 
       
  1818 on socket 0, and that the E: drive corresponds to the primary partition on 
       
  1819 socket 1 (a socket is a slot for removable media). This mapping may not always 
       
  1820 be the case because it is set up in the variant layer of the Symbian OS.
       
  1821 
       
  1822 This function assumes that the drive mappings are contiguous, starting 
       
  1823 from drive D: .
       
  1824 
       
  1825 On emulator:
       
  1826 The removable media is represented by drive X: only.
       
  1827 
       
  1828 @param aDriveUnit The drive to check.
       
  1829 @return ETrue if the drive is the primary partition in a removable media slot. 
       
  1830 ETrue is also returned if the drive is A, B or C:. EFalse is returned otherwise. */
       
  1831 	{ // static
       
  1832 	TDriveInfoV1Buf buf;
       
  1833 	UserHal::DriveInfo(buf);
       
  1834 
       
  1835 #ifdef __EPOC32__
       
  1836 	return ((aDriveUnit-EDriveC)<=buf().iTotalSockets);
       
  1837 #else // emulator
       
  1838     return (aDriveUnit==EDriveX || (aDriveUnit-EDriveC)<=buf().iTotalSockets);
       
  1839 #endif
       
  1840 	}
       
  1841 
       
  1842 EXPORT_C void BaflUtils::RemoveSystemDirectory(CDir& aDir)
       
  1843 /** Removes "System" from a list of directory entries. 
       
  1844 
       
  1845 @param aDir Array of directory entries. */
       
  1846 	{ // static
       
  1847 	STATIC_CAST(BaflDir&,aDir).RemoveSystem();
       
  1848 	}
       
  1849 
       
  1850 EXPORT_C TInt BaflUtils::SortByTable(CDir& aDir,CBaflFileSortTable* aTable)
       
  1851 /** Sorts files by UID.
       
  1852 
       
  1853 The caller supplies a table which specifies the order in which files are to 
       
  1854 be sorted. The files whose UID3 is the first UID in the table appear first. 
       
  1855 The files whose UID3 is the UID specified second appear next, and so on. Files 
       
  1856 whose UID3 is not specified in the table, and directories, appear at the end 
       
  1857 of the list, with directories preceding the files, and with files sorted in 
       
  1858 ascending order of UID3.
       
  1859 
       
  1860 This function is used for customising how lists of application files are sorted.
       
  1861 
       
  1862 @param aDir The array of files and directories to sort.
       
  1863 @param aTable A sort order table containing the UIDs to use in the sort.
       
  1864 @return KErrNone if successful, otherwise one of the standard error codes. */
       
  1865 	{ // static
       
  1866 	return STATIC_CAST(BaflDir&,aDir).SortByTable(aTable);
       
  1867 	}
       
  1868 
       
  1869 EXPORT_C void BaflUtils::GetDowngradePathL(const RFs& aFs, const TLanguage aCurrentLanguage, RArray<TLanguage>& aLanguageArray)
       
  1870 /** Gets the full language downgrade path for a particular locale.
       
  1871 
       
  1872 @param aFs A connected session with the file server.
       
  1873 @param aCurrentLanguage The language of the locale for which the language downgrade 
       
  1874 path is required. This language will always be returned as the first language 
       
  1875 in aLanguageArray. To get the downgrade path for the language of the current 
       
  1876 locale, specify the language returned by User::Language(). 
       
  1877 @param aLanguageArray On return, contains the language downgrade path.
       
  1878 @see BaflUtils::NearestLanguageFile() */
       
  1879  	{
       
  1880  	TLocale currentLocale; 
       
  1881   	TNearestLanguageFileFinder languageDowngradePath(aFs);
       
  1882   	TLanguage idealLanguage=IdealLanguage();
       
  1883   	MakeLanguageDowngradePath(languageDowngradePath.iPath,aCurrentLanguage,idealLanguage, currentLocale);
       
  1884  	aLanguageArray.Reset();
       
  1885   	const TLanguage* p=languageDowngradePath.iPath;
       
  1886   	while (*p != ELangNone)
       
  1887   		{
       
  1888 		User::LeaveIfError(aLanguageArray.Append(*p));
       
  1889   		++p;
       
  1890   		}
       
  1891  	}
       
  1892 
       
  1893 EXPORT_C void BaflUtils::PersistLocale()
       
  1894 /** Saves the locale settings in TLocale and the currency symbol to file. 
       
  1895 @deprecated 9.1
       
  1896 Persistence and initialisation of system locale data will be performed 
       
  1897 transparently by a separate executable (InilialiseLocale.exe) wich should 
       
  1898 be loaded as part of the system start procedure.
       
  1899 */
       
  1900 	{
       
  1901 // Replaced by new repository based locale initialisation mechanism.
       
  1902 	}
       
  1903 
       
  1904 
       
  1905 
       
  1906 EXPORT_C TInt BaflUtils::PersistHAL()
       
  1907 /** Saves the HAL settings to file. 
       
  1908 This will start a new executable and saves HAL attributes to a file, 
       
  1909 little delay because of the creation of new process
       
  1910 @return KErrNone if suceessful, otheriwse system wide error code.
       
  1911 */
       
  1912 	{
       
  1913 	RProcess process;
       
  1914 	_LIT(KHALSettings, "HALSettings.exe");
       
  1915 	_LIT(KCommandLine, "PERSIST");
       
  1916 	TInt result = process.Create(KHALSettings, KCommandLine);
       
  1917 	if(result != KErrNone )
       
  1918 		return result;
       
  1919 	TRequestStatus status;
       
  1920 	process.Logon(status);
       
  1921 	if ( status != KRequestPending)
       
  1922 		{
       
  1923 		process.Kill(0);		// abort 
       
  1924 		}
       
  1925 	else
       
  1926 		{
       
  1927 		process.Resume();	// logon OK
       
  1928 		}
       
  1929 	User::WaitForRequest(status);
       
  1930 	
       
  1931 	// we can't use the 'exit reason' if the exe panicked as this
       
  1932 	// is the panic 'reason' and may be '0' which cannot be distinguished
       
  1933 	// from KErrNone
       
  1934 	result = process.ExitType() == EExitPanic ? KErrGeneral : status.Int();
       
  1935 	process.Close();
       
  1936 	return result;
       
  1937 	}
       
  1938 
       
  1939 EXPORT_C void BaflUtils::PersistScreenCalibration(const TDigitizerCalibration& aScreenCalibration)
       
  1940 	{
       
  1941 	
       
  1942 	RFs	fs;
       
  1943 	TInt err = fs.Connect();
       
  1944 	if (err == KErrNone)
       
  1945 		{
       
  1946 		// Setting up drive to store Screen data
       
  1947 		TDriveUnit systemDrive(static_cast<TInt>(RFs::GetSystemDrive()));
       
  1948 		TBuf<KMaxDriveName+KScreenCalibrationPathLength>  ScreenFileNameWithDriveAndPath(systemDrive.Name());
       
  1949 		ScreenFileNameWithDriveAndPath.Append(KScreenCalibrationFolder);
       
  1950 		
       
  1951 		// Ensure directory \System\Data exists in target drive
       
  1952 		TRAP(err, EnsurePathExistsL(fs, ScreenFileNameWithDriveAndPath));
       
  1953 		if(err == KErrNone)
       
  1954 			{
       
  1955 			ScreenFileNameWithDriveAndPath.Append(KScreenCalibrationFileName);	
       
  1956 			
       
  1957 			RFile file;
       
  1958 			err = file.Replace(fs,ScreenFileNameWithDriveAndPath,EFileWrite|EFileShareExclusive);
       
  1959 			if (err == KErrNone)
       
  1960 				{
       
  1961 				// Write aScreenCalibration to file. 
       
  1962 				TPtrC8 calptr((const TUint8*)&aScreenCalibration, sizeof(TDigitizerCalibration));
       
  1963 				err = file.Write(calptr);
       
  1964 				}
       
  1965 			file.Close();
       
  1966 			}
       
  1967 		}
       
  1968 	fs.Close();
       
  1969 	}
       
  1970 
       
  1971 EXPORT_C void BaflUtils::InitialiseScreenCalibration(RFs& aFs)
       
  1972 	{
       
  1973 	TFindFile ff(aFs);
       
  1974 	if (ff.FindByDir(KScreenCalibrationFileName, KScreenCalibrationFolder)==KErrNone)
       
  1975 		{
       
  1976 		RFile file; 
       
  1977 		if (file.Open(aFs,ff.File(),EFileRead) == KErrNone )
       
  1978 			{
       
  1979 			TDigitizerCalibration calibrationSetting;
       
  1980 			TPtr8 scrcal((TUint8*)&calibrationSetting, sizeof(TDigitizerCalibration));
       
  1981 			if( file.Read(scrcal, sizeof( TDigitizerCalibration )) == KErrNone )
       
  1982 				UserHal::SetXYInputCalibration(calibrationSetting);
       
  1983 
       
  1984 			}
       
  1985 		file.Close();
       
  1986 		}
       
  1987 	}
       
  1988 
       
  1989 EXPORT_C void BaflUtils::InitialiseHAL(RFs&)
       
  1990 /** Initialise the HAL settings from. 
       
  1991 @deprecated 9.1
       
  1992 This function is empty
       
  1993 */
       
  1994 	{
       
  1995 	}
       
  1996 
       
  1997 EXPORT_C void BaflUtils::InitialiseLocale(RFs& /* aFs */) 
       
  1998 	{
       
  1999 // Replaced by new repository based locale initialisation mechanism.
       
  2000 	}
       
  2001 
       
  2002 
       
  2003 //
       
  2004 // class CEikFileSortTable
       
  2005 // 
       
  2006 
       
  2007 /**
       
  2008 */	
       
  2009 EXPORT_C CBaflFileSortTable::CBaflFileSortTable()
       
  2010 	: CArrayFixFlat<TUid>(EArrayGranularity)
       
  2011 	{}
       
  2012 
       
  2013 /**
       
  2014  * Loads the CBaflFileSortTable using the UIDs read from the TResourceReader supplied in aReader. 
       
  2015  * @param aReader TResourceReader from which UIDS are read.
       
  2016  * @leave KErrNoMemory if there is insufficient memory available or one of the system wide error codes.
       
  2017  */	
       
  2018 EXPORT_C void CBaflFileSortTable::ConstructFromResourceL(TResourceReader& aReader)
       
  2019 	{
       
  2020 	const TInt count=aReader.ReadInt16();
       
  2021 	for (TInt i=0;i<count;i++)
       
  2022 		AppendL(TUid::Uid(aReader.ReadInt32()));
       
  2023 	}
       
  2024 
       
  2025 //
       
  2026 // class BaflDir
       
  2027 //
       
  2028 
       
  2029 #define KSystemDirName _L("System") // Name for System directory
       
  2030 
       
  2031 
       
  2032 void BaflDir::RemoveSystem()
       
  2033 /*  Remove "System" if in list and it's a directory. */	
       
  2034 {
       
  2035 	TInt index;
       
  2036 	TEntry entry;
       
  2037 	entry.iName=KSystemDirName;
       
  2038 	TKeyArrayPak key(_FOFF(TEntry,iName),ECmpFolded);
       
  2039 	if (iArray->Find(entry,key,index)==KErrNone)
       
  2040 		{
       
  2041 		entry=(*iArray)[index];
       
  2042 		if (entry.IsDir())
       
  2043 			iArray->Delete(index);
       
  2044 		}
       
  2045 	};
       
  2046 
       
  2047 /*
       
  2048 This function gets the element at position "aPos" of aEntries array and inserts 
       
  2049 it to poition "aNewPos". The element size is "aSize". After the operation the array size
       
  2050 grows by 1, the element at "aPos" position  moves one position forward.
       
  2051 This function must be called only from BaflDir::SortByTable() and the insert position
       
  2052 is always less or equal than the position of the element to be inserted.
       
  2053 */
       
  2054 static void InsertL(CArrayPakFlat<TEntry>* aEntries, TInt aPos, TInt aNewPos, TInt aSize)
       
  2055 	{
       
  2056 	__ASSERT_DEBUG(aPos >= aNewPos, User::Invariant());
       
  2057 	//Expand the array adding one empty entry at "aNewPos" position.
       
  2058 	aEntries->ExpandL(aNewPos, aSize);
       
  2059 	//After successfull "ExpandL" call "aPos" must be incremented by 1.
       
  2060 	//Copy the entry from "aPos + 1" position to "aNewPos" position
       
  2061 	(*aEntries)[aNewPos] = (*aEntries)[++aPos];
       
  2062 	}
       
  2063 
       
  2064 /**
       
  2065 Copied from f32file.inl (now moved to f32file_private.h)
       
  2066 Returns the minimum uncompressed size of the TEntry object, including the valid 
       
  2067 portion of the name string. The returned value is aligned to 4-byte boundary and
       
  2068 length includes private members.
       
  2069 
       
  2070 @internalTechnology
       
  2071 @return minimum uncompressed size of TEntry object
       
  2072 */
       
  2073 
       
  2074 TInt BaflDir::MinEntrySize(const TEntry & aEntry)
       
  2075 	{
       
  2076 	return(sizeof(TUint)+sizeof(TInt)+sizeof(TTime)+sizeof(TInt)+sizeof(TUidType)+
       
  2077          Align4(aEntry.iName.Size()) + 2*sizeof(TInt));
       
  2078 	}
       
  2079 
       
  2080 TInt BaflDir::SortByTable(CBaflFileSortTable* aTable)
       
  2081 /**
       
  2082 Sort into order from given table.
       
  2083 Any file with uid[2] matching an entry in the table will be sorted relative to 
       
  2084 others in the table and before any files with no matching uid. 
       
  2085 For Example: Assume UID table is filled with below 2 UID's
       
  2086 table[0] =0x10003a64 and table[1] =0x10003a5c. Then file with UID[2]=0x10003a64 
       
  2087 will be sorted first in the list followed by file with UID[2]=0x10003a5c. Rest
       
  2088 files will be sorted in the ascending order of UID[2] with directories preceding
       
  2089 the files.
       
  2090 
       
  2091 @param aTable A sort order table containing the UIDs to use in the sort. 
       
  2092 @return KErrNone if suceessful, otheriwse another system-wide error code.
       
  2093 */
       
  2094 	{
       
  2095 	TInt r=this->Sort(EDirsFirst|ESortByUid);
       
  2096 	if(r != KErrNone)
       
  2097 		{
       
  2098 		return r;
       
  2099 		}
       
  2100 	const TInt tableCount=aTable->Count();
       
  2101 	const TInt count=iArray->Count();
       
  2102 	TInt sortedInsertionPoint = 0;
       
  2103 	for (TInt i=0;i<tableCount;i++)	
       
  2104 		{
       
  2105 		TUid	tableUid;
       
  2106 		// get each UID in the table
       
  2107 		tableUid = aTable->At(i);
       
  2108 		for (TInt j=sortedInsertionPoint;j<count;j++)
       
  2109 			{
       
  2110 			//parse files in the array list
       
  2111 			TEntry* pEntry=&(*iArray)[j];
       
  2112 			// check table UID for match with UID[2] of the file in the list
       
  2113 			// if found, move the file at the top in the list, followed by next matching UID
       
  2114 			if (tableUid == pEntry->iType[2])
       
  2115 				{
       
  2116 				TRAPD(insertErr, ::InsertL(iArray, j, sortedInsertionPoint++, MinEntrySize(*pEntry)));
       
  2117 				if(insertErr!=KErrNone)
       
  2118 					{
       
  2119 					return insertErr;
       
  2120 					}
       
  2121 				iArray->Delete(j+1);
       
  2122 				}
       
  2123 			}
       
  2124 		}
       
  2125 		iArray->Compress();
       
  2126 		return KErrNone;
       
  2127 	}