sl@0
|
1 |
// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
//
|
sl@0
|
15 |
|
sl@0
|
16 |
#include <bafl/langutil.h>
|
sl@0
|
17 |
#include <hal.h>
|
sl@0
|
18 |
#include <hal_data.h>
|
sl@0
|
19 |
#include "LangUtilImpl.h"
|
sl@0
|
20 |
|
sl@0
|
21 |
|
sl@0
|
22 |
/**
|
sl@0
|
23 |
Mimimum length of a filename and mimimum length of a suffix.
|
sl@0
|
24 |
Note these two values are tied together.
|
sl@0
|
25 |
*/
|
sl@0
|
26 |
const TInt KInvNameAndMinSuffixLength = 2;
|
sl@0
|
27 |
|
sl@0
|
28 |
#define ISDIGIT(c) (c-'0' >= 0 && c-'0' <= 9)
|
sl@0
|
29 |
|
sl@0
|
30 |
_LIT(KAllDrives, "YXWVUTSRQPONMLKJIHGFEDCBAZ");
|
sl@0
|
31 |
|
sl@0
|
32 |
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 };
|
sl@0
|
33 |
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 };
|
sl@0
|
34 |
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 };
|
sl@0
|
35 |
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 };
|
sl@0
|
36 |
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 };
|
sl@0
|
37 |
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 };
|
sl@0
|
38 |
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 };
|
sl@0
|
39 |
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 };
|
sl@0
|
40 |
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 };
|
sl@0
|
41 |
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 };
|
sl@0
|
42 |
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 };
|
sl@0
|
43 |
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 };
|
sl@0
|
44 |
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 };
|
sl@0
|
45 |
LOCAL_C const TLanguage dp13[] = { ELangInternationalFrench,ELangFrench,ELangSwissFrench,ELangBelgianFrench,ELangCanadianFrench,ELangNone };
|
sl@0
|
46 |
LOCAL_C const TLanguage dp14[] = { ELangBelgianFrench, ELangFrench,ELangInternationalFrench,ELangSwissFrench,ELangCanadianFrench,ELangNone };
|
sl@0
|
47 |
LOCAL_C const TLanguage dp15[] = { ELangCanadianFrench, ELangFrench,ELangInternationalFrench,ELangSwissFrench,ELangBelgianFrench,ELangNone };
|
sl@0
|
48 |
LOCAL_C const TLanguage dp16[] = { ELangFrench,ELangInternationalFrench,ELangSwissFrench,ELangBelgianFrench,ELangCanadianFrench,ELangNone };
|
sl@0
|
49 |
LOCAL_C const TLanguage dp17[] = { ELangSwissFrench,ELangFrench,ELangInternationalFrench,ELangBelgianFrench,ELangCanadianFrench,ELangNone };
|
sl@0
|
50 |
LOCAL_C const TLanguage dp18[] = { ELangSwissGerman,ELangGerman,ELangAustrian,ELangNone };
|
sl@0
|
51 |
LOCAL_C const TLanguage dp19[] = { ELangAustrian,ELangGerman,ELangSwissGerman,ELangNone };
|
sl@0
|
52 |
LOCAL_C const TLanguage dp20[] = { ELangGerman,ELangSwissGerman,ELangAustrian,ELangNone };
|
sl@0
|
53 |
LOCAL_C const TLanguage dp21[] = { ELangSerbian,ELangCroatian,ELangNone };
|
sl@0
|
54 |
LOCAL_C const TLanguage dp22[] = { ELangCroatian,ELangSerbian,ELangNone };
|
sl@0
|
55 |
LOCAL_C const TLanguage dp23[] = { ELangRomanian,ELangMoldavian,ELangNone };
|
sl@0
|
56 |
LOCAL_C const TLanguage dp24[] = { ELangMoldavian,ELangRomanian,ELangNone };
|
sl@0
|
57 |
LOCAL_C const TLanguage dp25[] = { ELangBelgianFlemish,ELangDutch,ELangNone };
|
sl@0
|
58 |
LOCAL_C const TLanguage dp26[] = { ELangDutch,ELangBelgianFlemish,ELangNone };
|
sl@0
|
59 |
LOCAL_C const TLanguage dp27[] = { ELangAfrikaans,ELangDutch,ELangNone };
|
sl@0
|
60 |
LOCAL_C const TLanguage dp28[] = { ELangMalay_Apac,ELangMalay,ELangNone };
|
sl@0
|
61 |
LOCAL_C const TLanguage dp29[] = { ELangIndonesian_Apac,ELangIndonesian,ELangNone };
|
sl@0
|
62 |
LOCAL_C const TLanguage dp30[] = { ELangSpanish,ELangInternationalSpanish,ELangLatinAmericanSpanish,ELangNone };
|
sl@0
|
63 |
LOCAL_C const TLanguage dp31[] = { ELangLatinAmericanSpanish,ELangSpanish,ELangInternationalSpanish,ELangNone };
|
sl@0
|
64 |
LOCAL_C const TLanguage dp32[] = { ELangInternationalSpanish,ELangSpanish,ELangLatinAmericanSpanish,ELangNone };
|
sl@0
|
65 |
LOCAL_C const TLanguage dp33[] = { ELangCyprusGreek,ELangGreek,ELangNone };
|
sl@0
|
66 |
LOCAL_C const TLanguage dp34[] = { ELangGreek,ELangCyprusGreek,ELangNone };
|
sl@0
|
67 |
LOCAL_C const TLanguage dp35[] = { ELangSwissItalian,ELangItalian,ELangNone };
|
sl@0
|
68 |
LOCAL_C const TLanguage dp36[] = { ELangItalian,ELangSwissItalian,ELangNone };
|
sl@0
|
69 |
LOCAL_C const TLanguage dp37[] = { ELangBrazilianPortuguese,ELangPortuguese,ELangNone };
|
sl@0
|
70 |
LOCAL_C const TLanguage dp38[] = { ELangPortuguese,ELangBrazilianPortuguese,ELangNone };
|
sl@0
|
71 |
LOCAL_C const TLanguage dp39[] = { ELangFinlandSwedish,ELangSwedish,ELangNone };
|
sl@0
|
72 |
LOCAL_C const TLanguage dp40[] = { ELangSwedish,ELangFinlandSwedish,ELangNone };
|
sl@0
|
73 |
LOCAL_C const TLanguage dp41[] = { ELangCyprusTurkish,ELangTurkish,ELangNone };
|
sl@0
|
74 |
LOCAL_C const TLanguage dp42[] = { ELangTurkish,ELangCyprusTurkish,ELangNone };
|
sl@0
|
75 |
LOCAL_C const TLanguage dp43[] = { ELangHongKongChinese, ELangTaiwanChinese, ELangPrcChinese,ELangNone };
|
sl@0
|
76 |
LOCAL_C const TLanguage dp44[] = { ELangTaiwanChinese, ELangHongKongChinese,ELangPrcChinese,ELangNone };
|
sl@0
|
77 |
LOCAL_C const TLanguage dp45[] = { ELangPrcChinese, ELangHongKongChinese, ELangTaiwanChinese,ELangNone };
|
sl@0
|
78 |
LOCAL_C const TLanguage * const KEquivalentLists[] = { dp0, dp1, dp2, dp3, dp4, dp5, dp6,
|
sl@0
|
79 |
dp7, dp8, dp9, dp10, dp11, dp12, dp13, dp14, dp15, dp16, dp17,
|
sl@0
|
80 |
dp18, dp19, dp20, dp21, dp22, dp23, dp24, dp25, dp26, dp27,
|
sl@0
|
81 |
dp28, dp29, dp30, dp31, dp32, dp33, dp34, dp35, dp36, dp37,
|
sl@0
|
82 |
dp38, dp39, dp40, dp41, dp42, dp43, dp44, dp45};
|
sl@0
|
83 |
|
sl@0
|
84 |
|
sl@0
|
85 |
|
sl@0
|
86 |
LOCAL_C TBool IsLanguageExtended(const TLanguage aLanguage)
|
sl@0
|
87 |
{
|
sl@0
|
88 |
// For compatibility reasons, ELangNone is 0xFFFF. However, it's not an extended language.
|
sl@0
|
89 |
if ((aLanguage==ELangNone) || ((static_cast<TUint>(aLanguage))<=KDialectMask))
|
sl@0
|
90 |
return EFalse;
|
sl@0
|
91 |
else
|
sl@0
|
92 |
return ETrue;
|
sl@0
|
93 |
}
|
sl@0
|
94 |
|
sl@0
|
95 |
|
sl@0
|
96 |
LOCAL_C TLanguage BaseLanguage(const TLanguage aLanguage)
|
sl@0
|
97 |
{
|
sl@0
|
98 |
if (IsLanguageExtended(aLanguage))
|
sl@0
|
99 |
return static_cast<TLanguage>(aLanguage & KDialectMask);
|
sl@0
|
100 |
else
|
sl@0
|
101 |
return aLanguage;
|
sl@0
|
102 |
}
|
sl@0
|
103 |
|
sl@0
|
104 |
LOCAL_C TLanguage NextLanguage(TLanguage aLanguage)
|
sl@0
|
105 |
/** Returns the next best language to use after aLanguage,
|
sl@0
|
106 |
based on Symbian's base table of language near-equivalence.
|
sl@0
|
107 |
@internalAll */
|
sl@0
|
108 |
{
|
sl@0
|
109 |
switch (aLanguage)
|
sl@0
|
110 |
{
|
sl@0
|
111 |
case ELangAustralian:
|
sl@0
|
112 |
case ELangNewZealand:
|
sl@0
|
113 |
case ELangSouthAfricanEnglish:
|
sl@0
|
114 |
case ELangInternationalEnglish:
|
sl@0
|
115 |
case ELangAmerican:
|
sl@0
|
116 |
case ELangEnglish_Apac:
|
sl@0
|
117 |
case ELangEnglish_Taiwan:
|
sl@0
|
118 |
case ELangEnglish_HongKong:
|
sl@0
|
119 |
case ELangEnglish_Prc:
|
sl@0
|
120 |
case ELangEnglish_Japan:
|
sl@0
|
121 |
case ELangEnglish_Thailand:
|
sl@0
|
122 |
return ELangEnglish;
|
sl@0
|
123 |
case ELangCanadianEnglish:
|
sl@0
|
124 |
return ELangAmerican; // 2-stage downgrade
|
sl@0
|
125 |
case ELangSwissFrench:
|
sl@0
|
126 |
case ELangBelgianFrench:
|
sl@0
|
127 |
case ELangInternationalFrench:
|
sl@0
|
128 |
case ELangCanadianFrench:
|
sl@0
|
129 |
return ELangFrench;
|
sl@0
|
130 |
case ELangSwissGerman:
|
sl@0
|
131 |
case ELangAustrian:
|
sl@0
|
132 |
return ELangGerman;
|
sl@0
|
133 |
case ELangInternationalSpanish:
|
sl@0
|
134 |
case ELangLatinAmericanSpanish:
|
sl@0
|
135 |
return ELangSpanish;
|
sl@0
|
136 |
case ELangSwissItalian:
|
sl@0
|
137 |
return ELangItalian;
|
sl@0
|
138 |
case ELangFinlandSwedish:
|
sl@0
|
139 |
return ELangSwedish;
|
sl@0
|
140 |
case ELangCyprusTurkish:
|
sl@0
|
141 |
return ELangTurkish;
|
sl@0
|
142 |
case ELangBelgianFlemish:
|
sl@0
|
143 |
return ELangDutch;
|
sl@0
|
144 |
case ELangHongKongChinese:
|
sl@0
|
145 |
return ELangTaiwanChinese;
|
sl@0
|
146 |
case ELangCyprusGreek:
|
sl@0
|
147 |
return ELangGreek;
|
sl@0
|
148 |
case ELangMalay_Apac:
|
sl@0
|
149 |
return ELangMalay;
|
sl@0
|
150 |
case ELangBrazilianPortuguese:
|
sl@0
|
151 |
return ELangPortuguese;
|
sl@0
|
152 |
default:
|
sl@0
|
153 |
return ELangNone;
|
sl@0
|
154 |
}
|
sl@0
|
155 |
}
|
sl@0
|
156 |
|
sl@0
|
157 |
|
sl@0
|
158 |
void AddLanguage(TLanguagePath& aPath, TLanguage aNewLanguage)
|
sl@0
|
159 |
/** Add language to the language path if there is space.
|
sl@0
|
160 |
The first empty slot must have "ELangNone" in it. This will also be true
|
sl@0
|
161 |
on exit. */
|
sl@0
|
162 |
{
|
sl@0
|
163 |
TLanguage *p = aPath;
|
sl@0
|
164 |
const TLanguage *end = &(aPath[KMaxDowngradeLanguages]);
|
sl@0
|
165 |
while (p != end)
|
sl@0
|
166 |
{
|
sl@0
|
167 |
if (*p == aNewLanguage)
|
sl@0
|
168 |
// language already in list
|
sl@0
|
169 |
break;
|
sl@0
|
170 |
if (*p == ELangNone)
|
sl@0
|
171 |
{
|
sl@0
|
172 |
// found the end of the list
|
sl@0
|
173 |
p[0] = aNewLanguage;
|
sl@0
|
174 |
p[1] = ELangNone;
|
sl@0
|
175 |
break;
|
sl@0
|
176 |
}
|
sl@0
|
177 |
++p;
|
sl@0
|
178 |
}
|
sl@0
|
179 |
return;
|
sl@0
|
180 |
}
|
sl@0
|
181 |
|
sl@0
|
182 |
void MakeLanguageDowngradePath(TLanguagePath& aPath,
|
sl@0
|
183 |
TLanguage aCurrent, TLanguage aIdeal, const TLocale& aLocale)
|
sl@0
|
184 |
{
|
sl@0
|
185 |
TInt j = 0;
|
sl@0
|
186 |
if( aIdeal != ELangNone)
|
sl@0
|
187 |
{
|
sl@0
|
188 |
aPath[j++]=aIdeal;
|
sl@0
|
189 |
}
|
sl@0
|
190 |
aPath[j++] = aCurrent;
|
sl@0
|
191 |
aPath[j++] = ELangNone;
|
sl@0
|
192 |
|
sl@0
|
193 |
if (aCurrent & ~KDialectMask)
|
sl@0
|
194 |
AddLanguage(aPath, static_cast<TLanguage>(aCurrent & KDialectMask));
|
sl@0
|
195 |
|
sl@0
|
196 |
for (TInt i=0;i<=2;i++)
|
sl@0
|
197 |
{
|
sl@0
|
198 |
AddLanguage(aPath, aLocale.LanguageDowngrade(i));
|
sl@0
|
199 |
AddLanguage(aPath, BaseLanguage(aLocale.LanguageDowngrade(i)));
|
sl@0
|
200 |
}
|
sl@0
|
201 |
|
sl@0
|
202 |
while (ELangNone != (aCurrent = NextLanguage(BaseLanguage(aCurrent))))
|
sl@0
|
203 |
AddLanguage(aPath, aCurrent);
|
sl@0
|
204 |
}
|
sl@0
|
205 |
|
sl@0
|
206 |
|
sl@0
|
207 |
|
sl@0
|
208 |
//EXPORT_C
|
sl@0
|
209 |
void LangUtil::GetDowngradePathL(const RFs& aFs, const TLanguage aCurrentLanguage, RArray<TLanguage>& aLanguageArray){
|
sl@0
|
210 |
|
sl@0
|
211 |
TLocale currentLocale;
|
sl@0
|
212 |
TNearestLanguageFileFinder languageDowngradePath(aFs);
|
sl@0
|
213 |
TLanguage idealLanguage=IdealLanguage();
|
sl@0
|
214 |
MakeLanguageDowngradePath(languageDowngradePath.iPath,aCurrentLanguage,idealLanguage, currentLocale);
|
sl@0
|
215 |
aLanguageArray.Reset();
|
sl@0
|
216 |
const TLanguage* p=languageDowngradePath.iPath;
|
sl@0
|
217 |
while (*p != ELangNone)
|
sl@0
|
218 |
{
|
sl@0
|
219 |
User::LeaveIfError(aLanguageArray.Append(*p));
|
sl@0
|
220 |
++p;
|
sl@0
|
221 |
}
|
sl@0
|
222 |
|
sl@0
|
223 |
}
|
sl@0
|
224 |
|
sl@0
|
225 |
|
sl@0
|
226 |
//EXPORT_C
|
sl@0
|
227 |
void LangUtil::GetEquivalentLanguageList(TLanguage aLang, TLanguagePath& aEquivalents){
|
sl@0
|
228 |
|
sl@0
|
229 |
aEquivalents[0] = aLang;
|
sl@0
|
230 |
aEquivalents[1] = ELangNone;
|
sl@0
|
231 |
const TInt len = sizeof(KEquivalentLists) / sizeof(KEquivalentLists[0]);
|
sl@0
|
232 |
for (TInt i = 0; i < len; ++i)
|
sl@0
|
233 |
{
|
sl@0
|
234 |
const TLanguage *ptr = KEquivalentLists[i];
|
sl@0
|
235 |
if (ptr[0] == aLang)
|
sl@0
|
236 |
{
|
sl@0
|
237 |
TInt index = 1;
|
sl@0
|
238 |
while (ELangNone != *ptr)
|
sl@0
|
239 |
{
|
sl@0
|
240 |
aEquivalents[index++] = (TLanguage)*(++ptr);
|
sl@0
|
241 |
}
|
sl@0
|
242 |
aEquivalents[index] = ELangNone;
|
sl@0
|
243 |
break;
|
sl@0
|
244 |
} // end if ptr[0]
|
sl@0
|
245 |
} // end for i
|
sl@0
|
246 |
|
sl@0
|
247 |
}
|
sl@0
|
248 |
|
sl@0
|
249 |
|
sl@0
|
250 |
|
sl@0
|
251 |
//EXPORT_C
|
sl@0
|
252 |
TLanguage LangUtil::IdealLanguage(){
|
sl@0
|
253 |
|
sl@0
|
254 |
TLanguage* langPtr=(TLanguage*)Dll::Tls();
|
sl@0
|
255 |
|
sl@0
|
256 |
if( langPtr==NULL)
|
sl@0
|
257 |
{
|
sl@0
|
258 |
return(ELangNone);
|
sl@0
|
259 |
}
|
sl@0
|
260 |
|
sl@0
|
261 |
return(*langPtr);
|
sl@0
|
262 |
|
sl@0
|
263 |
}
|
sl@0
|
264 |
|
sl@0
|
265 |
|
sl@0
|
266 |
//EXPORT_C
|
sl@0
|
267 |
void LangUtil::NearestLanguageFile(const RFs& aFs, TFileName& aName){
|
sl@0
|
268 |
|
sl@0
|
269 |
TLanguage language;
|
sl@0
|
270 |
|
sl@0
|
271 |
NearestLanguageFile( aFs, aName, language);
|
sl@0
|
272 |
|
sl@0
|
273 |
(void)language;
|
sl@0
|
274 |
|
sl@0
|
275 |
}
|
sl@0
|
276 |
|
sl@0
|
277 |
|
sl@0
|
278 |
//EXPORT_C
|
sl@0
|
279 |
void LangUtil::NearestLanguageFile(const RFs& aFs, TFileName& aName, TLanguage& aLanguage){
|
sl@0
|
280 |
#if defined(DO_PROFILING)
|
sl@0
|
281 |
RDebug::ProfileReset(FIRST_PROFILE_INDEX, PROFILE_COUNT);
|
sl@0
|
282 |
RDebug::ProfileStart(PROFILE_INDEX_1);
|
sl@0
|
283 |
#endif
|
sl@0
|
284 |
TNearestLanguageFileFinder finder(aFs);
|
sl@0
|
285 |
TBool goodSuffix=finder.SetFileName(aName);
|
sl@0
|
286 |
|
sl@0
|
287 |
// Only continue if the suffix is good.
|
sl@0
|
288 |
if(goodSuffix)
|
sl@0
|
289 |
{
|
sl@0
|
290 |
// add preset customised resource drive to drive list
|
sl@0
|
291 |
// Note that errors returned from AddCustomResourceDrive are ignored. This is because if
|
sl@0
|
292 |
// a custom resource drive has not been found we still want to continue on with searching
|
sl@0
|
293 |
// other drives according to our algorithm
|
sl@0
|
294 |
finder.AddCustomResourceDrive();
|
sl@0
|
295 |
|
sl@0
|
296 |
TLocale locale;
|
sl@0
|
297 |
TLanguage idealLanguage;
|
sl@0
|
298 |
idealLanguage = IdealLanguage();
|
sl@0
|
299 |
MakeLanguageDowngradePath(finder.iPath, User::Language(), idealLanguage, locale);
|
sl@0
|
300 |
if (!finder.FindLanguageAndDrive()
|
sl@0
|
301 |
&& KErrNone != finder.FindFirstLanguageFileAndDrive())
|
sl@0
|
302 |
finder.RepairFileName();
|
sl@0
|
303 |
aLanguage = finder.Language();
|
sl@0
|
304 |
}
|
sl@0
|
305 |
|
sl@0
|
306 |
#if defined(DO_PROFILING)
|
sl@0
|
307 |
RDebug::ProfileEnd(PROFILE_INDEX_1);
|
sl@0
|
308 |
TProfile profile[PROFILE_COUNT];
|
sl@0
|
309 |
RDebug::ProfileResult(&profile[0], FIRST_PROFILE_INDEX, PROFILE_COUNT);
|
sl@0
|
310 |
if(goodSuffix)
|
sl@0
|
311 |
{
|
sl@0
|
312 |
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);
|
sl@0
|
313 |
}
|
sl@0
|
314 |
else
|
sl@0
|
315 |
{
|
sl@0
|
316 |
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);
|
sl@0
|
317 |
}
|
sl@0
|
318 |
#endif
|
sl@0
|
319 |
|
sl@0
|
320 |
}
|
sl@0
|
321 |
|
sl@0
|
322 |
|
sl@0
|
323 |
//EXPORT_C
|
sl@0
|
324 |
void LangUtil::NearestLanguageFileV2(const RFs& aFs, TFileName& aName, TLanguage& aLanguage){
|
sl@0
|
325 |
|
sl@0
|
326 |
TNearestLanguageFileFinder finder(aFs);
|
sl@0
|
327 |
TBool goodSuffix=finder.SetFileName(aName);
|
sl@0
|
328 |
|
sl@0
|
329 |
// Continue only if the suffix is good.
|
sl@0
|
330 |
if(goodSuffix)
|
sl@0
|
331 |
{
|
sl@0
|
332 |
// add preset customised resource drive to drive list
|
sl@0
|
333 |
// Note that errors returned from AddCustomResourceDrive are ignored. This is because if
|
sl@0
|
334 |
// a custom resource drive has not been found we still want to continue on with searching
|
sl@0
|
335 |
// other drives according to our algorithm
|
sl@0
|
336 |
finder.AddCustomResourceDrive();
|
sl@0
|
337 |
|
sl@0
|
338 |
GetEquivalentLanguageList(User::Language(), finder.iPath);
|
sl@0
|
339 |
if (!finder.FindLanguageAndDrive()
|
sl@0
|
340 |
&& KErrNone != finder.FindFirstLanguageFileAndDrive())
|
sl@0
|
341 |
finder.RepairFileName();
|
sl@0
|
342 |
aLanguage = finder.Language();
|
sl@0
|
343 |
}
|
sl@0
|
344 |
else
|
sl@0
|
345 |
{
|
sl@0
|
346 |
aLanguage = ELangNone;
|
sl@0
|
347 |
}
|
sl@0
|
348 |
|
sl@0
|
349 |
}
|
sl@0
|
350 |
|
sl@0
|
351 |
|
sl@0
|
352 |
//EXPORT_C
|
sl@0
|
353 |
void LangUtil::ReleaseIdealLanguage(){
|
sl@0
|
354 |
|
sl@0
|
355 |
TLanguage* aLanguage=(TLanguage*)Dll::Tls();
|
sl@0
|
356 |
if( aLanguage==NULL)
|
sl@0
|
357 |
return;
|
sl@0
|
358 |
|
sl@0
|
359 |
delete aLanguage;
|
sl@0
|
360 |
Dll::FreeTls();
|
sl@0
|
361 |
|
sl@0
|
362 |
}
|
sl@0
|
363 |
|
sl@0
|
364 |
|
sl@0
|
365 |
//EXPORT_C
|
sl@0
|
366 |
TInt LangUtil::SetIdealLanguage(TLanguage aLanguage){
|
sl@0
|
367 |
TLanguage* langPtr=(TLanguage*)Dll::Tls();
|
sl@0
|
368 |
if( langPtr==NULL)
|
sl@0
|
369 |
{
|
sl@0
|
370 |
langPtr=(TLanguage*)User::Alloc(sizeof(TLanguage));
|
sl@0
|
371 |
|
sl@0
|
372 |
if(!langPtr)
|
sl@0
|
373 |
return(KErrNoMemory);
|
sl@0
|
374 |
|
sl@0
|
375 |
TInt ret=Dll::SetTls(langPtr);
|
sl@0
|
376 |
|
sl@0
|
377 |
if(ret!=KErrNone)
|
sl@0
|
378 |
return(ret);
|
sl@0
|
379 |
}
|
sl@0
|
380 |
*langPtr=aLanguage;
|
sl@0
|
381 |
return(KErrNone);
|
sl@0
|
382 |
|
sl@0
|
383 |
}
|
sl@0
|
384 |
|
sl@0
|
385 |
TInt RRealDirectoryScanner::Open(RFs& aFs, const TDesC& aMatchPattern)
|
sl@0
|
386 |
{
|
sl@0
|
387 |
return iDir.Open(aFs, aMatchPattern,
|
sl@0
|
388 |
KEntryAttReadOnly | KEntryAttHidden | KEntryAttSystem | KEntryAttArchive);
|
sl@0
|
389 |
}
|
sl@0
|
390 |
|
sl@0
|
391 |
TInt RRealDirectoryScanner::Next(TEntry& aOut)
|
sl@0
|
392 |
{
|
sl@0
|
393 |
return iDir.Read(aOut);
|
sl@0
|
394 |
}
|
sl@0
|
395 |
|
sl@0
|
396 |
void RRealDirectoryScanner::Close()
|
sl@0
|
397 |
{
|
sl@0
|
398 |
iDir.Close();
|
sl@0
|
399 |
}
|
sl@0
|
400 |
|
sl@0
|
401 |
/**
|
sl@0
|
402 |
Simply counts the number of numerical characters at the end of the name passed.
|
sl@0
|
403 |
|
sl@0
|
404 |
@internalComponent
|
sl@0
|
405 |
@param aFilename The filename to parse
|
sl@0
|
406 |
|
sl@0
|
407 |
@return Count of the numeric digits at the end of the name passed,
|
sl@0
|
408 |
e.g. x.r491 gives 3.
|
sl@0
|
409 |
*/
|
sl@0
|
410 |
TInt TNearestLanguageFileFinder::CountDigitsFromEnd(const TDesC& aFilename)
|
sl@0
|
411 |
{
|
sl@0
|
412 |
TInt digitCount = 0;
|
sl@0
|
413 |
|
sl@0
|
414 |
for (TInt idx = aFilename.Length()-1; idx>=0 && ISDIGIT (aFilename [idx]); --idx)
|
sl@0
|
415 |
{
|
sl@0
|
416 |
++digitCount;
|
sl@0
|
417 |
}
|
sl@0
|
418 |
|
sl@0
|
419 |
return digitCount;
|
sl@0
|
420 |
}
|
sl@0
|
421 |
|
sl@0
|
422 |
|
sl@0
|
423 |
/**
|
sl@0
|
424 |
Counts the number of digits at the end of a filename.
|
sl@0
|
425 |
|
sl@0
|
426 |
@internalComponent
|
sl@0
|
427 |
@param aFilename The filename to parse
|
sl@0
|
428 |
|
sl@0
|
429 |
@return Count of the numeric digits at the end of the suffix,
|
sl@0
|
430 |
e.g. x.r491 gives 3.
|
sl@0
|
431 |
0 if no numeric end of suffix,
|
sl@0
|
432 |
KErrBadName for an invalid filename,
|
sl@0
|
433 |
KErrNotSupported if the filename (minus path) is less
|
sl@0
|
434 |
than or equal to KInvNameAndMinSuffixLength in length
|
sl@0
|
435 |
*/
|
sl@0
|
436 |
TInt TNearestLanguageFileFinder::CountDigitsFromEndInSuffix (const TDesC& aFilename)
|
sl@0
|
437 |
{
|
sl@0
|
438 |
TInt digitCount = 0;
|
sl@0
|
439 |
TInt slashIdx = 0;
|
sl@0
|
440 |
TInt len = aFilename.Length ();
|
sl@0
|
441 |
|
sl@0
|
442 |
// NOTE: We didn't use TChar here as they are too slow.
|
sl@0
|
443 |
// We also didn't use TParse as they are too large.
|
sl@0
|
444 |
|
sl@0
|
445 |
// don't work on the path
|
sl@0
|
446 |
for (slashIdx=len-1; slashIdx >= 0 && aFilename[slashIdx] != '\\'; --slashIdx)
|
sl@0
|
447 |
{/*do nothing*/};
|
sl@0
|
448 |
|
sl@0
|
449 |
// Get new length
|
sl@0
|
450 |
if (slashIdx>=0) {len = len-slashIdx-1;}
|
sl@0
|
451 |
|
sl@0
|
452 |
// Initial test to see if filename legal size.
|
sl@0
|
453 |
if (len > KInvNameAndMinSuffixLength)
|
sl@0
|
454 |
{
|
sl@0
|
455 |
digitCount = CountDigitsFromEnd(aFilename);
|
sl@0
|
456 |
|
sl@0
|
457 |
// Can't store something bigger or we'll panic!
|
sl@0
|
458 |
if (digitCount > KMaxSuffixLength)
|
sl@0
|
459 |
{
|
sl@0
|
460 |
digitCount = KErrBadName;
|
sl@0
|
461 |
}
|
sl@0
|
462 |
else
|
sl@0
|
463 |
// numeric filename, e.g. "1234".
|
sl@0
|
464 |
// No preceeding alpha character
|
sl@0
|
465 |
if (!(len-digitCount))
|
sl@0
|
466 |
{
|
sl@0
|
467 |
digitCount = KErrBadName;
|
sl@0
|
468 |
}
|
sl@0
|
469 |
}
|
sl@0
|
470 |
else
|
sl@0
|
471 |
{
|
sl@0
|
472 |
digitCount = KErrNotSupported;
|
sl@0
|
473 |
}
|
sl@0
|
474 |
|
sl@0
|
475 |
return digitCount;
|
sl@0
|
476 |
}
|
sl@0
|
477 |
|
sl@0
|
478 |
RDirectoryScanner& TNearestLanguageFileFinder::DirectoryScanner()
|
sl@0
|
479 |
{
|
sl@0
|
480 |
return iDirScanner;
|
sl@0
|
481 |
}
|
sl@0
|
482 |
|
sl@0
|
483 |
TBool TNearestLanguageFileFinder::FileExists(const TDesC& aFileName) const
|
sl@0
|
484 |
{
|
sl@0
|
485 |
//return BaflUtils::FileExists(iFs, aFileName);
|
sl@0
|
486 |
TEntry entry;
|
sl@0
|
487 |
return(iFs.Entry(aFileName,entry)==KErrNone);
|
sl@0
|
488 |
|
sl@0
|
489 |
}
|
sl@0
|
490 |
|
sl@0
|
491 |
TBool TNearestLanguageFileFinder::FindDrive()
|
sl@0
|
492 |
{
|
sl@0
|
493 |
ASSERT(iFileName);
|
sl@0
|
494 |
TBool found=EFalse;
|
sl@0
|
495 |
TInt driveLength=iDrives.Length();
|
sl@0
|
496 |
for (TInt drive = 0; drive!=driveLength; ++drive)
|
sl@0
|
497 |
{
|
sl@0
|
498 |
(*iFileName)[0] = iDrives[drive];
|
sl@0
|
499 |
if (FileExists(*iFileName))
|
sl@0
|
500 |
{
|
sl@0
|
501 |
found=ETrue;
|
sl@0
|
502 |
break;
|
sl@0
|
503 |
}
|
sl@0
|
504 |
}
|
sl@0
|
505 |
return found;
|
sl@0
|
506 |
}
|
sl@0
|
507 |
|
sl@0
|
508 |
TBool TNearestLanguageFileFinder::AppendLanguageCode(TLanguage aLanguage)
|
sl@0
|
509 |
{
|
sl@0
|
510 |
TInt rest = static_cast<TInt>(aLanguage);
|
sl@0
|
511 |
#ifdef _DEBUG
|
sl@0
|
512 |
_LIT(KErrorMessage, "Bafl");
|
sl@0
|
513 |
#endif
|
sl@0
|
514 |
__ASSERT_DEBUG(0 <= rest, User::Panic(KErrorMessage,KErrArgument));
|
sl@0
|
515 |
iFileName->SetLength(iBaseLength);
|
sl@0
|
516 |
const TInt remaining = iFileName->MaxLength() - iBaseLength;
|
sl@0
|
517 |
TInt soFar = 0;
|
sl@0
|
518 |
TBuf<1> num;
|
sl@0
|
519 |
num.Append('0');
|
sl@0
|
520 |
TBool appendLangSuccess = ETrue;
|
sl@0
|
521 |
TInt digitCount = 0;
|
sl@0
|
522 |
TInt digit = 0;
|
sl@0
|
523 |
while (rest)
|
sl@0
|
524 |
{
|
sl@0
|
525 |
if (remaining == soFar)
|
sl@0
|
526 |
{
|
sl@0
|
527 |
// no more room in descriptor- return rather than panic,
|
sl@0
|
528 |
// file cannot exist.
|
sl@0
|
529 |
iFileName->SetLength(iBaseLength);
|
sl@0
|
530 |
appendLangSuccess= EFalse;
|
sl@0
|
531 |
break;
|
sl@0
|
532 |
}
|
sl@0
|
533 |
// Convert the number to ASCII by consistantly getting the base 10 remainder to convert.
|
sl@0
|
534 |
// The number is updated minus the remainder for the next iteration.
|
sl@0
|
535 |
// eg (rest = 123) -> (12, r3) -> (1, r2) -> (0, r1)
|
sl@0
|
536 |
// Then insert the ASCII representation of the remainder into the filename end
|
sl@0
|
537 |
// so it appears the correct way round.
|
sl@0
|
538 |
// eg (filename.r) -> (filename.r3) -> (filename.r23) -> (filename.r123)
|
sl@0
|
539 |
digit = rest % 10;
|
sl@0
|
540 |
digitCount++;
|
sl@0
|
541 |
rest /= 10;
|
sl@0
|
542 |
num[0] = static_cast<TText16>(digit + '0');
|
sl@0
|
543 |
iFileName->Insert(iBaseLength, num);
|
sl@0
|
544 |
|
sl@0
|
545 |
// Minimum suffix length is KInvNameAndMinSuffixLength
|
sl@0
|
546 |
// so we have to insert zeros to make this up.
|
sl@0
|
547 |
while (!rest && digitCount < KInvNameAndMinSuffixLength)
|
sl@0
|
548 |
{
|
sl@0
|
549 |
num[0] = static_cast<TText16>('0');
|
sl@0
|
550 |
iFileName->Insert(iBaseLength, num);
|
sl@0
|
551 |
++digitCount;
|
sl@0
|
552 |
}
|
sl@0
|
553 |
|
sl@0
|
554 |
++soFar;
|
sl@0
|
555 |
}
|
sl@0
|
556 |
|
sl@0
|
557 |
return appendLangSuccess;
|
sl@0
|
558 |
}
|
sl@0
|
559 |
|
sl@0
|
560 |
|
sl@0
|
561 |
TBool TNearestLanguageFileFinder::FindLanguageAndDrive()
|
sl@0
|
562 |
/** Search for files across all drives in all languages in the path plus the
|
sl@0
|
563 |
language-neutral file. */
|
sl@0
|
564 |
{
|
sl@0
|
565 |
ASSERT(iFileName);
|
sl@0
|
566 |
// No point appending if the suffix is bad
|
sl@0
|
567 |
for (const TLanguage* currentLang = iPath; *currentLang != ELangNone; ++currentLang)
|
sl@0
|
568 |
{
|
sl@0
|
569 |
if (AppendLanguageCode(*currentLang) && FindDrive())
|
sl@0
|
570 |
{
|
sl@0
|
571 |
iLanguage = *currentLang;
|
sl@0
|
572 |
return ETrue;
|
sl@0
|
573 |
}
|
sl@0
|
574 |
}
|
sl@0
|
575 |
// search for language-neutral file
|
sl@0
|
576 |
iFileName->SetLength(iBaseLength);
|
sl@0
|
577 |
iFileName->Append(iSuffix);
|
sl@0
|
578 |
return FindDrive();
|
sl@0
|
579 |
}
|
sl@0
|
580 |
|
sl@0
|
581 |
TInt TNearestLanguageFileFinder::LanguageNumberFromFile(const TDesC& aFileName, const TDesC& aStem)
|
sl@0
|
582 |
{
|
sl@0
|
583 |
TInt lang = 0;
|
sl@0
|
584 |
TInt multiplier = 1;
|
sl@0
|
585 |
TInt leadingZeroCount = 0;
|
sl@0
|
586 |
TInt languageNumber = KErrNotFound;
|
sl@0
|
587 |
const TText* firstChar = aFileName.Ptr();
|
sl@0
|
588 |
const TText* lastChar = firstChar + aFileName.Length() - 1;
|
sl@0
|
589 |
const TText* currentChar = lastChar;
|
sl@0
|
590 |
// string cannot contain only numbers, because it must have a ':' in it
|
sl@0
|
591 |
while ('0' <= *currentChar && *currentChar <= '9')
|
sl@0
|
592 |
{
|
sl@0
|
593 |
if (*currentChar == '0')
|
sl@0
|
594 |
leadingZeroCount++;
|
sl@0
|
595 |
else
|
sl@0
|
596 |
{
|
sl@0
|
597 |
leadingZeroCount = 0;
|
sl@0
|
598 |
lang += multiplier * (*currentChar - '0');
|
sl@0
|
599 |
}
|
sl@0
|
600 |
multiplier *= 10;
|
sl@0
|
601 |
--currentChar;
|
sl@0
|
602 |
}
|
sl@0
|
603 |
TInt along=lastChar - currentChar;
|
sl@0
|
604 |
if (2 <= along)
|
sl@0
|
605 |
{
|
sl@0
|
606 |
// We have at least 2 digits at the end.
|
sl@0
|
607 |
// trim of bad leading zeros
|
sl@0
|
608 |
TInt maxTrim = along - 2;
|
sl@0
|
609 |
if (maxTrim < leadingZeroCount)
|
sl@0
|
610 |
{
|
sl@0
|
611 |
leadingZeroCount = maxTrim;
|
sl@0
|
612 |
}
|
sl@0
|
613 |
currentChar += leadingZeroCount;
|
sl@0
|
614 |
// we have at least 2 digits at the end but does the rest of it match the stem?
|
sl@0
|
615 |
TPtrC foundStem(firstChar, currentChar - firstChar + 1);
|
sl@0
|
616 |
//foundStem.CompareF(aStem.Right(foundStem.Length()))
|
sl@0
|
617 |
if (0 == foundStem.CompareF(aStem))
|
sl@0
|
618 |
{
|
sl@0
|
619 |
languageNumber=lang;
|
sl@0
|
620 |
}
|
sl@0
|
621 |
}
|
sl@0
|
622 |
return languageNumber;
|
sl@0
|
623 |
}
|
sl@0
|
624 |
|
sl@0
|
625 |
TInt TNearestLanguageFileFinder::FindFirstLanguageFile(RFs& aFs)
|
sl@0
|
626 |
{
|
sl@0
|
627 |
ASSERT(iFileName);
|
sl@0
|
628 |
iFileName->SetLength(iBaseLength);
|
sl@0
|
629 |
TPtrC name(*iFileName);
|
sl@0
|
630 |
TParsePtrC nameToParse(name);
|
sl@0
|
631 |
TPtrC nameStem(nameToParse.NameAndExt());
|
sl@0
|
632 |
iFileName->Append('*');
|
sl@0
|
633 |
TInt bestLanguageMatch = KMaxTInt;
|
sl@0
|
634 |
RDirectoryScanner& scanner = DirectoryScanner();
|
sl@0
|
635 |
TInt err = scanner.Open(aFs, *iFileName);
|
sl@0
|
636 |
if (err != KErrNone)
|
sl@0
|
637 |
{
|
sl@0
|
638 |
return err;
|
sl@0
|
639 |
}
|
sl@0
|
640 |
TEntry entry;
|
sl@0
|
641 |
while (KErrNone == scanner.Next(entry))
|
sl@0
|
642 |
{
|
sl@0
|
643 |
TInt lang = LanguageNumberFromFile(entry.iName, nameStem);
|
sl@0
|
644 |
if (0 < lang && lang < bestLanguageMatch)
|
sl@0
|
645 |
{
|
sl@0
|
646 |
bestLanguageMatch = lang;
|
sl@0
|
647 |
}
|
sl@0
|
648 |
}
|
sl@0
|
649 |
scanner.Close();
|
sl@0
|
650 |
if (bestLanguageMatch != KMaxTInt)
|
sl@0
|
651 |
{
|
sl@0
|
652 |
iLanguage = static_cast<TLanguage>(bestLanguageMatch);
|
sl@0
|
653 |
AppendLanguageCode(static_cast<TLanguage>(bestLanguageMatch));
|
sl@0
|
654 |
return KErrNone;
|
sl@0
|
655 |
}
|
sl@0
|
656 |
return KErrNotFound;
|
sl@0
|
657 |
}
|
sl@0
|
658 |
|
sl@0
|
659 |
// Try each drive for any language files
|
sl@0
|
660 |
// iFileName must have a directory specifier
|
sl@0
|
661 |
TInt TNearestLanguageFileFinder::FindFirstLanguageFileAndDrive()
|
sl@0
|
662 |
{
|
sl@0
|
663 |
ASSERT(iFileName);
|
sl@0
|
664 |
TInt findFirstResult=KErrNotFound;
|
sl@0
|
665 |
TInt driveLength=iDrives.Length();
|
sl@0
|
666 |
for (TInt drive = 0; drive != driveLength; ++drive)
|
sl@0
|
667 |
{
|
sl@0
|
668 |
(*iFileName)[0] = iDrives[drive];
|
sl@0
|
669 |
TInt err = FindFirstLanguageFile(CONST_CAST(RFs&,iFs));
|
sl@0
|
670 |
if (err == KErrNone || err == KErrNoMemory)
|
sl@0
|
671 |
{
|
sl@0
|
672 |
findFirstResult=err;
|
sl@0
|
673 |
break;
|
sl@0
|
674 |
}
|
sl@0
|
675 |
}
|
sl@0
|
676 |
return findFirstResult;
|
sl@0
|
677 |
}
|
sl@0
|
678 |
|
sl@0
|
679 |
/**
|
sl@0
|
680 |
Invalid filenames are any filename whose length (minus path) must be greater
|
sl@0
|
681 |
than KInvNameAndMinSuffixLength, and whose form is purely numerical, i.e. '1234'
|
sl@0
|
682 |
*/
|
sl@0
|
683 |
TBool TNearestLanguageFileFinder::SetFileName(TFileName& aFileName)
|
sl@0
|
684 |
{
|
sl@0
|
685 |
iDrives.Zero();
|
sl@0
|
686 |
iFileName = &aFileName;
|
sl@0
|
687 |
iOriginalBaseLength = iFileName->Length();
|
sl@0
|
688 |
|
sl@0
|
689 |
TInt suffixLength = CountDigitsFromEndInSuffix (aFileName);
|
sl@0
|
690 |
|
sl@0
|
691 |
// No point trying for filenames thats are badly formed
|
sl@0
|
692 |
// or that are too large.
|
sl@0
|
693 |
if (suffixLength >= 0 &&
|
sl@0
|
694 |
KInvNameAndMinSuffixLength < iOriginalBaseLength)
|
sl@0
|
695 |
{
|
sl@0
|
696 |
if (suffixLength > 0)
|
sl@0
|
697 |
{
|
sl@0
|
698 |
// all of suffix to be replaced
|
sl@0
|
699 |
iSuffix = iFileName->Right(suffixLength);
|
sl@0
|
700 |
iOriginalBaseLength -= suffixLength;
|
sl@0
|
701 |
iFileName->SetLength(iOriginalBaseLength);
|
sl@0
|
702 |
}
|
sl@0
|
703 |
else
|
sl@0
|
704 |
{
|
sl@0
|
705 |
// No numerical part to suffix
|
sl@0
|
706 |
TInt periodIdx = 0;
|
sl@0
|
707 |
|
sl@0
|
708 |
// Search for the period within range KInvNameAndMinSuffixLength
|
sl@0
|
709 |
// from the end. As this must work for all values of
|
sl@0
|
710 |
// KInvNameAndMinSuffixLength
|
sl@0
|
711 |
for (TInt i = iOriginalBaseLength-1;
|
sl@0
|
712 |
!periodIdx && i >= (iOriginalBaseLength-KInvNameAndMinSuffixLength-1);
|
sl@0
|
713 |
--i)
|
sl@0
|
714 |
{
|
sl@0
|
715 |
if ((*iFileName) [i] == '.')
|
sl@0
|
716 |
{
|
sl@0
|
717 |
periodIdx = i;
|
sl@0
|
718 |
}
|
sl@0
|
719 |
}
|
sl@0
|
720 |
|
sl@0
|
721 |
// Don't handle files ending in a period.
|
sl@0
|
722 |
// This is because the behaviour is different between Windows
|
sl@0
|
723 |
// and Symbian Fs. In Windows it strips the period off.
|
sl@0
|
724 |
//
|
sl@0
|
725 |
// However, and this shouldn't happen as it is not shown
|
sl@0
|
726 |
// (in the documentation) to be valid.
|
sl@0
|
727 |
// Just try our best.
|
sl@0
|
728 |
if (periodIdx == iOriginalBaseLength-1)
|
sl@0
|
729 |
{
|
sl@0
|
730 |
iSuffix.Zero();
|
sl@0
|
731 |
return EFalse;
|
sl@0
|
732 |
}
|
sl@0
|
733 |
else
|
sl@0
|
734 |
if (periodIdx)
|
sl@0
|
735 |
{
|
sl@0
|
736 |
// If there are KInvNameAndMinSuffixLength chars after the period
|
sl@0
|
737 |
// simply replace them.
|
sl@0
|
738 |
TInt right = iOriginalBaseLength-periodIdx-1;
|
sl@0
|
739 |
iSuffix = iFileName->Right(right);
|
sl@0
|
740 |
iOriginalBaseLength -= right;
|
sl@0
|
741 |
iFileName->SetLength(iOriginalBaseLength);
|
sl@0
|
742 |
}
|
sl@0
|
743 |
else
|
sl@0
|
744 |
{
|
sl@0
|
745 |
// Make the suffix start from KInvNameAndMinSuffixLength
|
sl@0
|
746 |
// from the right
|
sl@0
|
747 |
TInt right = KInvNameAndMinSuffixLength;
|
sl@0
|
748 |
iSuffix = iFileName->Right(right);
|
sl@0
|
749 |
iOriginalBaseLength -= right;
|
sl@0
|
750 |
iFileName->SetLength(iOriginalBaseLength);
|
sl@0
|
751 |
}
|
sl@0
|
752 |
}
|
sl@0
|
753 |
}
|
sl@0
|
754 |
else
|
sl@0
|
755 |
{
|
sl@0
|
756 |
// bad or no suffix - treat the same
|
sl@0
|
757 |
iSuffix.Zero();
|
sl@0
|
758 |
return EFalse;
|
sl@0
|
759 |
}
|
sl@0
|
760 |
|
sl@0
|
761 |
// For filenames with no drive letter prefix and also for filenames
|
sl@0
|
762 |
// shorter than the drive letter length, i.e. with no drive
|
sl@0
|
763 |
// information, insert it.
|
sl@0
|
764 |
// Handles if the user simply enters the drive, e.g. "c:".
|
sl@0
|
765 |
if (iOriginalBaseLength < KMaxDriveName || (*iFileName)[1] != ':')
|
sl@0
|
766 |
{
|
sl@0
|
767 |
// Set up the default if none supplied and make room in the filename
|
sl@0
|
768 |
// array to contain a drive specification. Set initial drive letter to -1
|
sl@0
|
769 |
// so the iFileName is repaired before exited
|
sl@0
|
770 |
iInitialDriveLetter = -1;
|
sl@0
|
771 |
iFileName->Insert(0, _L("_:"));
|
sl@0
|
772 |
iDrives.Append('Z');
|
sl@0
|
773 |
}
|
sl@0
|
774 |
else
|
sl@0
|
775 |
{
|
sl@0
|
776 |
// Use the drive supplied inthe aName to NearestLanguageFile()
|
sl@0
|
777 |
iInitialDriveLetter = (*iFileName)[0];
|
sl@0
|
778 |
iDrives.Append(iInitialDriveLetter);
|
sl@0
|
779 |
}
|
sl@0
|
780 |
|
sl@0
|
781 |
iBaseLength = iFileName->Length();
|
sl@0
|
782 |
|
sl@0
|
783 |
return ETrue;
|
sl@0
|
784 |
}
|
sl@0
|
785 |
|
sl@0
|
786 |
|
sl@0
|
787 |
TLanguage TNearestLanguageFileFinder::Language()
|
sl@0
|
788 |
{
|
sl@0
|
789 |
return iLanguage;
|
sl@0
|
790 |
}
|
sl@0
|
791 |
|
sl@0
|
792 |
TNearestLanguageFileFinder::TNearestLanguageFileFinder(
|
sl@0
|
793 |
const RFs& aFs)
|
sl@0
|
794 |
: iFs(aFs), iFileName(0), iLanguage(ELangNone)
|
sl@0
|
795 |
{
|
sl@0
|
796 |
}
|
sl@0
|
797 |
|
sl@0
|
798 |
void TNearestLanguageFileFinder::RepairFileName()
|
sl@0
|
799 |
{
|
sl@0
|
800 |
ASSERT(iFileName);
|
sl@0
|
801 |
iFileName->SetLength(iBaseLength);
|
sl@0
|
802 |
if (iInitialDriveLetter == -1)
|
sl@0
|
803 |
iFileName->Delete(0, 2);
|
sl@0
|
804 |
else
|
sl@0
|
805 |
(*iFileName)[0] = static_cast<TText>(iInitialDriveLetter);
|
sl@0
|
806 |
iFileName->SetLength(iOriginalBaseLength);
|
sl@0
|
807 |
iFileName->Append(iSuffix);
|
sl@0
|
808 |
}
|
sl@0
|
809 |
|
sl@0
|
810 |
|
sl@0
|
811 |
/**
|
sl@0
|
812 |
Add the custom resource drive to the start of the iDrives string.
|
sl@0
|
813 |
|
sl@0
|
814 |
The custom resource drive is a preset writeable drive on which customised
|
sl@0
|
815 |
resource files may be present. This drive takes priority over the other
|
sl@0
|
816 |
drives when searching for language files.
|
sl@0
|
817 |
|
sl@0
|
818 |
@return KErrNone if iDrives string was successfully modified; KErrAlreadyExists
|
sl@0
|
819 |
if the drive is already present in the string; otherwise one of
|
sl@0
|
820 |
the other system-wide error codes (iDrives will be unmodified).
|
sl@0
|
821 |
*/
|
sl@0
|
822 |
TInt TNearestLanguageFileFinder::AddCustomResourceDrive()
|
sl@0
|
823 |
{
|
sl@0
|
824 |
TInt drive = GetCustomResourceDriveNumber();
|
sl@0
|
825 |
if (drive<0)
|
sl@0
|
826 |
return drive;
|
sl@0
|
827 |
|
sl@0
|
828 |
// if drive not already in drive list
|
sl@0
|
829 |
if (iDrives.LocateF('A' + drive) < 0)
|
sl@0
|
830 |
{
|
sl@0
|
831 |
// add it
|
sl@0
|
832 |
_LIT(KDrivePlaceholder, "_");
|
sl@0
|
833 |
iDrives.Insert(0, KDrivePlaceholder);
|
sl@0
|
834 |
iDrives[0] = 'A' + drive;
|
sl@0
|
835 |
return KErrNone;
|
sl@0
|
836 |
}
|
sl@0
|
837 |
else
|
sl@0
|
838 |
return KErrAlreadyExists;
|
sl@0
|
839 |
}
|
sl@0
|
840 |
|
sl@0
|
841 |
|
sl@0
|
842 |
void TNearestLanguageFileFinder::AddAllDrives()
|
sl@0
|
843 |
{
|
sl@0
|
844 |
ASSERT(iDrives.Length() < 2);
|
sl@0
|
845 |
if (iDrives.Length() == 0)
|
sl@0
|
846 |
{
|
sl@0
|
847 |
iDrives = KAllDrives;
|
sl@0
|
848 |
return;
|
sl@0
|
849 |
}
|
sl@0
|
850 |
TInt pos = KAllDrives().LocateF(iDrives[0]);
|
sl@0
|
851 |
if (pos < 0)
|
sl@0
|
852 |
{
|
sl@0
|
853 |
iDrives = KAllDrives;
|
sl@0
|
854 |
return;
|
sl@0
|
855 |
}
|
sl@0
|
856 |
iDrives.Append(KAllDrives().Left(pos));
|
sl@0
|
857 |
iDrives.Append(KAllDrives().Mid(pos + 1));
|
sl@0
|
858 |
}
|
sl@0
|
859 |
|
sl@0
|
860 |
|
sl@0
|
861 |
/**
|
sl@0
|
862 |
Get the value of the custom resource drive.
|
sl@0
|
863 |
|
sl@0
|
864 |
The custom resource drive is a preset writeable drive on which customised language resource
|
sl@0
|
865 |
files can reside. The drive number is accessed via the HAL attribute ECustomResourceDrive.
|
sl@0
|
866 |
It is then returned if it has been defined as a valid drive no.
|
sl@0
|
867 |
Otherwise for backward compatibility reasons an attempt is then made to access the system
|
sl@0
|
868 |
drive HAL attribute instead. This drive number is returned if it has been defined as a valid
|
sl@0
|
869 |
drive number.
|
sl@0
|
870 |
Otherwise if neither a valid ECustomResourceDrive or ESystemDrive exists then KErrNotFound
|
sl@0
|
871 |
is returned.
|
sl@0
|
872 |
|
sl@0
|
873 |
Note that the ESystemDrive HAL attribute has been deprecated. It is accessed here to cater
|
sl@0
|
874 |
for existing implementations which still expect it to be used.
|
sl@0
|
875 |
|
sl@0
|
876 |
@return The drive number (corresponding to a TDriveNumber value) if successful;
|
sl@0
|
877 |
KErrNotFound if neither a valid ECustomResourceDrive or a valid ESystemDrive HAL attribute
|
sl@0
|
878 |
is defined;
|
sl@0
|
879 |
|
sl@0
|
880 |
@see HAL::ECustomResourceDrive
|
sl@0
|
881 |
@see HAL::ESystemDrive
|
sl@0
|
882 |
*/
|
sl@0
|
883 |
TInt TNearestLanguageFileFinder::GetCustomResourceDriveNumber() const
|
sl@0
|
884 |
{
|
sl@0
|
885 |
TInt drive = KErrNotFound;
|
sl@0
|
886 |
|
sl@0
|
887 |
// access custom resource drive attribute
|
sl@0
|
888 |
if (HAL::Get(HAL::ECustomResourceDrive, drive) == KErrNone)
|
sl@0
|
889 |
{
|
sl@0
|
890 |
// check that drive is valid
|
sl@0
|
891 |
if (drive>=EDriveA && drive<=EDriveZ)
|
sl@0
|
892 |
return drive;
|
sl@0
|
893 |
}
|
sl@0
|
894 |
|
sl@0
|
895 |
// access system drive attribute
|
sl@0
|
896 |
// (Note that ESystemDrive is deprecated. It is checked here
|
sl@0
|
897 |
// solely for backward compatibility reasons.)
|
sl@0
|
898 |
if (HAL::Get(HAL::ESystemDrive, drive) == KErrNone)
|
sl@0
|
899 |
{
|
sl@0
|
900 |
// check that drive is valid
|
sl@0
|
901 |
if (drive>=EDriveA && drive<=EDriveZ)
|
sl@0
|
902 |
return drive;
|
sl@0
|
903 |
}
|
sl@0
|
904 |
|
sl@0
|
905 |
return KErrNotFound;
|
sl@0
|
906 |
}
|
sl@0
|
907 |
|
sl@0
|
908 |
|