1*449ab281SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*449ab281SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*449ab281SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*449ab281SAndrew Rist  * distributed with this work for additional information
6*449ab281SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*449ab281SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*449ab281SAndrew Rist  * "License"); you may not use this file except in compliance
9*449ab281SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*449ab281SAndrew Rist  *
11*449ab281SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*449ab281SAndrew Rist  *
13*449ab281SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*449ab281SAndrew Rist  * software distributed under the License is distributed on an
15*449ab281SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*449ab281SAndrew Rist  * KIND, either express or implied.  See the License for the
17*449ab281SAndrew Rist  * specific language governing permissions and limitations
18*449ab281SAndrew Rist  * under the License.
19*449ab281SAndrew Rist  *
20*449ab281SAndrew Rist  *************************************************************/
21*449ab281SAndrew Rist 
22*449ab281SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_i18npool.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include "transliterationImpl.hxx"
28cdf0e10cSrcweir #include "servicename.hxx"
29cdf0e10cSrcweir 
30cdf0e10cSrcweir #include <com/sun/star/i18n/TransliterationType.hpp>
31cdf0e10cSrcweir #include <com/sun/star/lang/XComponent.hpp>
32cdf0e10cSrcweir #include <com/sun/star/container/XContentEnumerationAccess.hpp>
33cdf0e10cSrcweir #include <com/sun/star/container/XEnumeration.hpp>
34cdf0e10cSrcweir #include <com/sun/star/lang/XServiceInfo.hpp>
35cdf0e10cSrcweir #include <com/sun/star/lang/XSingleServiceFactory.hpp>
36cdf0e10cSrcweir 
37cdf0e10cSrcweir #include <comphelper/processfactory.hxx>
38cdf0e10cSrcweir #include <rtl/string.h>
39cdf0e10cSrcweir #include <rtl/ustring.hxx>
40cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
41cdf0e10cSrcweir 
42cdf0e10cSrcweir #include <algorithm>
43cdf0e10cSrcweir 
44cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
45cdf0e10cSrcweir #include <stdio.h>
46cdf0e10cSrcweir #endif
47cdf0e10cSrcweir 
48cdf0e10cSrcweir using namespace com::sun::star::uno;
49cdf0e10cSrcweir using namespace com::sun::star::lang;
50cdf0e10cSrcweir using namespace rtl;
51cdf0e10cSrcweir using namespace com::sun::star::container;
52cdf0e10cSrcweir 
53cdf0e10cSrcweir namespace com { namespace sun { namespace star { namespace i18n {
54cdf0e10cSrcweir 
55cdf0e10cSrcweir #define ERROR RuntimeException()
56cdf0e10cSrcweir 
57cdf0e10cSrcweir #define TmItem1( name ) \
58cdf0e10cSrcweir   {TransliterationModules_##name, TransliterationModulesNew_##name, #name}
59cdf0e10cSrcweir 
60cdf0e10cSrcweir #define TmItem2( name ) \
61cdf0e10cSrcweir   {(TransliterationModules)0, TransliterationModulesNew_##name, #name}
62cdf0e10cSrcweir 
63cdf0e10cSrcweir // Ignore Module list
64cdf0e10cSrcweir static struct TMlist {
65cdf0e10cSrcweir   TransliterationModules        tm;
66cdf0e10cSrcweir   TransliterationModulesNew     tmn;
67cdf0e10cSrcweir   const sal_Char               *implName;
68cdf0e10cSrcweir } TMlist[] = {                                  //      Modules      ModulesNew
69cdf0e10cSrcweir   TmItem1 (IGNORE_CASE),                        // 0. (1<<8        256) (7)
70cdf0e10cSrcweir   TmItem1 (IGNORE_WIDTH),                       // 1. (1<<9        512) (8)
71cdf0e10cSrcweir   TmItem1 (IGNORE_KANA),                        // 2. (1<<10      1024) (9)
72cdf0e10cSrcweir // No enum define for this trans. application has to use impl name to load it
73cdf0e10cSrcweir //  TmItem1 (IGNORE_CASE_SIMPLE),                       // (1<<11      1024) (66)
74cdf0e10cSrcweir 
75cdf0e10cSrcweir   TmItem1 (ignoreTraditionalKanji_ja_JP),       // 3. (1<<12      4096) (10)
76cdf0e10cSrcweir   TmItem1 (ignoreTraditionalKana_ja_JP),        // 4. (1<<13      8192) (11)
77cdf0e10cSrcweir   TmItem1 (ignoreMinusSign_ja_JP),              // 5. (1<<13     16384) (12)
78cdf0e10cSrcweir   TmItem1 (ignoreIterationMark_ja_JP),          // 6. (1<<14     32768) (13)
79cdf0e10cSrcweir   TmItem1 (ignoreSeparator_ja_JP),              // 7. (1<<15     65536) (14)
80cdf0e10cSrcweir   TmItem1 (ignoreSize_ja_JP),                   // 15. (1<<23  16777216) (22)
81cdf0e10cSrcweir   TmItem1 (ignoreMiddleDot_ja_JP),              // 17. (1<<25  67108864) (24)
82cdf0e10cSrcweir   TmItem1 (ignoreSpace_ja_JP),                  // 18. (1<<26 134217728) (25)
83cdf0e10cSrcweir   TmItem1 (ignoreZiZu_ja_JP),                   // 8. (1<<16    131072) (15)
84cdf0e10cSrcweir   TmItem1 (ignoreBaFa_ja_JP),                   // 9. (1<<17    262144) (16)
85cdf0e10cSrcweir   TmItem1 (ignoreTiJi_ja_JP),                   // 10. (1<<18    524288) (17)
86cdf0e10cSrcweir   TmItem1 (ignoreHyuByu_ja_JP),                 // 11. (1<<19   1048576) (18)
87cdf0e10cSrcweir   TmItem1 (ignoreSeZe_ja_JP),                   // 12. (1<<20   2097152) (19)
88cdf0e10cSrcweir   TmItem1 (ignoreIandEfollowedByYa_ja_JP),      // 13. (1<<21   4194304) (20)
89cdf0e10cSrcweir   TmItem1 (ignoreKiKuFollowedBySa_ja_JP),       // 14. (1<<22   8388608) (21)
90cdf0e10cSrcweir   TmItem1 (ignoreProlongedSoundMark_ja_JP),     // 16. (1<<24  33554432) (23)
91cdf0e10cSrcweir 
92cdf0e10cSrcweir   TmItem1 (UPPERCASE_LOWERCASE),        // 19. (1) (1)
93cdf0e10cSrcweir   TmItem1 (LOWERCASE_UPPERCASE),        // 20. (2) (2)
94cdf0e10cSrcweir   TmItem1 (HALFWIDTH_FULLWIDTH),        // 21. (3) (3)
95cdf0e10cSrcweir   TmItem1 (FULLWIDTH_HALFWIDTH),        // 22. (4) (4)
96cdf0e10cSrcweir   TmItem1 (KATAKANA_HIRAGANA),          // 23. (5) (5)
97cdf0e10cSrcweir   TmItem1 (HIRAGANA_KATAKANA),          // 24. (6) (6)
98cdf0e10cSrcweir 
99cdf0e10cSrcweir   TmItem1 (smallToLarge_ja_JP),         // 25. (1<<27 268435456) (26)
100cdf0e10cSrcweir   TmItem1 (largeToSmall_ja_JP),         // 26. (1<<28 536870912) (27)
101cdf0e10cSrcweir   TmItem2 (NumToTextLower_zh_CN),       // 27. () (28)
102cdf0e10cSrcweir   TmItem2 (NumToTextUpper_zh_CN),       // 28. () (29)
103cdf0e10cSrcweir   TmItem2 (NumToTextLower_zh_TW),       // 29. () (30)
104cdf0e10cSrcweir   TmItem2 (NumToTextUpper_zh_TW),       // 30. () (31)
105cdf0e10cSrcweir   TmItem2 (NumToTextFormalHangul_ko),   // 31. () (32)
106cdf0e10cSrcweir   TmItem2 (NumToTextFormalLower_ko),    // 32. () (33)
107cdf0e10cSrcweir   TmItem2 (NumToTextFormalUpper_ko),    // 33. () (34)
108cdf0e10cSrcweir   TmItem2 (NumToTextInformalHangul_ko), // 34. () (35)
109cdf0e10cSrcweir   TmItem2 (NumToTextInformalLower_ko),  // 35. () (36)
110cdf0e10cSrcweir   TmItem2 (NumToTextInformalUpper_ko),  // 36. () (37)
111cdf0e10cSrcweir   TmItem2 (NumToCharLower_zh_CN),       // 37. () (38)
112cdf0e10cSrcweir   TmItem2 (NumToCharUpper_zh_CN),       // 38. () (39)
113cdf0e10cSrcweir   TmItem2 (NumToCharLower_zh_TW),       // 39. () (40)
114cdf0e10cSrcweir   TmItem2 (NumToCharUpper_zh_TW),       // 40. () (41)
115cdf0e10cSrcweir   TmItem2 (NumToCharHangul_ko),         // 41. () (42)
116cdf0e10cSrcweir   TmItem2 (NumToCharLower_ko),          // 42. () (43)
117cdf0e10cSrcweir   TmItem2 (NumToCharUpper_ko),          // 43. () (44)
118cdf0e10cSrcweir   TmItem2 (NumToCharFullwidth),         // 44. () (45)
119cdf0e10cSrcweir   TmItem2 (NumToCharKanjiShort_ja_JP),  // 45. () (46)
120cdf0e10cSrcweir   TmItem2 (TextToNumLower_zh_CN),       // 46. () (47)
121cdf0e10cSrcweir   TmItem2 (TextToNumUpper_zh_CN),       // 47. () (48)
122cdf0e10cSrcweir   TmItem2 (TextToNumLower_zh_TW),       // 48. () (49)
123cdf0e10cSrcweir   TmItem2 (TextToNumUpper_zh_TW),       // 49. () (50)
124cdf0e10cSrcweir   TmItem2 (TextToNumFormalHangul_ko),   // 50. () (51)
125cdf0e10cSrcweir   TmItem2 (TextToNumFormalLower_ko),    // 51. () (52)
126cdf0e10cSrcweir   TmItem2 (TextToNumFormalUpper_ko),    // 52. () (53)
127cdf0e10cSrcweir   TmItem2 (TextToNumInformalHangul_ko), // 53. () (54)
128cdf0e10cSrcweir   TmItem2 (TextToNumInformalLower_ko),  // 54. () (55)
129cdf0e10cSrcweir   TmItem2 (TextToNumInformalUpper_ko),  // 55. () (56)
130cdf0e10cSrcweir 
131cdf0e10cSrcweir   TmItem2 (CharToNumLower_zh_CN),       // 56. () (59)
132cdf0e10cSrcweir   TmItem2 (CharToNumUpper_zh_CN),       // 57. () (60)
133cdf0e10cSrcweir   TmItem2 (CharToNumLower_zh_TW),       // 58. () (61)
134cdf0e10cSrcweir   TmItem2 (CharToNumUpper_zh_TW),       // 59. () (62)
135cdf0e10cSrcweir   TmItem2 (CharToNumHangul_ko),         // 60. () (63)
136cdf0e10cSrcweir   TmItem2 (CharToNumLower_ko),          // 61. () (64)
137cdf0e10cSrcweir   TmItem2 (CharToNumUpper_ko),          // 62. () (65)
138cdf0e10cSrcweir 
139cdf0e10cSrcweir // no enum defined for these trans. application has to use impl name to load them
140cdf0e10cSrcweir //  TmItem2 (NumToCharArabic_Indic),    // () (67)
141cdf0e10cSrcweir //  TmItem2 (NumToCharEstern_Arabic_Indic),// () (68)
142cdf0e10cSrcweir //  TmItem2 (NumToCharIndic),           // () (69)
143cdf0e10cSrcweir //  TmItem2 (NumToCharThai),            // () (70)
144cdf0e10cSrcweir   {(TransliterationModules)0, (TransliterationModulesNew)0,  NULL}
145cdf0e10cSrcweir };
146cdf0e10cSrcweir 
147cdf0e10cSrcweir TransliterationImpl::TransBody TransliterationImpl::lastTransBody;
148cdf0e10cSrcweir 
149cdf0e10cSrcweir // Constructor/Destructor
150cdf0e10cSrcweir TransliterationImpl::TransliterationImpl(const Reference <XMultiServiceFactory>& xMSF) : xSMgr(xMSF)
151cdf0e10cSrcweir {
152cdf0e10cSrcweir     numCascade = 0;
153cdf0e10cSrcweir     caseignoreOnly = sal_True;
154cdf0e10cSrcweir 
155cdf0e10cSrcweir     if ( xMSF.is() )
156cdf0e10cSrcweir     {
157cdf0e10cSrcweir         Reference < XInterface > xI=
158cdf0e10cSrcweir                 xMSF->createInstance(OUString::createFromAscii("com.sun.star.i18n.LocaleData"));
159cdf0e10cSrcweir         if ( xI.is() ) {
160cdf0e10cSrcweir             Any x = xI->queryInterface( ::getCppuType( (const uno::Reference< i18n::XLocaleData >*)0) );
161cdf0e10cSrcweir             x >>= localedata;
162cdf0e10cSrcweir         }
163cdf0e10cSrcweir     }
164cdf0e10cSrcweir }
165cdf0e10cSrcweir 
166cdf0e10cSrcweir TransliterationImpl::~TransliterationImpl()
167cdf0e10cSrcweir {
168cdf0e10cSrcweir     localedata.clear();
169cdf0e10cSrcweir     clear();
170cdf0e10cSrcweir }
171cdf0e10cSrcweir 
172cdf0e10cSrcweir 
173cdf0e10cSrcweir // Methods
174cdf0e10cSrcweir OUString SAL_CALL
175cdf0e10cSrcweir TransliterationImpl::getName() throw(RuntimeException)
176cdf0e10cSrcweir {
177cdf0e10cSrcweir     if (numCascade == 1 && bodyCascade[0].is())
178cdf0e10cSrcweir         return bodyCascade[0]->getName();
179cdf0e10cSrcweir     if (numCascade < 1)
180cdf0e10cSrcweir         return ( OUString::createFromAscii("Not Loaded"));
181cdf0e10cSrcweir     throw ERROR;
182cdf0e10cSrcweir }
183cdf0e10cSrcweir 
184cdf0e10cSrcweir sal_Int16 SAL_CALL
185cdf0e10cSrcweir TransliterationImpl::getType() throw(RuntimeException)
186cdf0e10cSrcweir {
187cdf0e10cSrcweir     if (numCascade > 1)
188cdf0e10cSrcweir         return (TransliterationType::CASCADE|TransliterationType::IGNORE);
189cdf0e10cSrcweir     if (numCascade > 0 && bodyCascade[0].is())
190cdf0e10cSrcweir         return(bodyCascade[0]->getType());
191cdf0e10cSrcweir     throw ERROR;
192cdf0e10cSrcweir }
193cdf0e10cSrcweir 
194cdf0e10cSrcweir void SAL_CALL
195cdf0e10cSrcweir TransliterationImpl::loadModule( TransliterationModules modType, const Locale& rLocale )
196cdf0e10cSrcweir         throw(RuntimeException)
197cdf0e10cSrcweir {
198cdf0e10cSrcweir         clear();
199cdf0e10cSrcweir     if (modType&TransliterationModules_IGNORE_MASK && modType&TransliterationModules_NON_IGNORE_MASK) {
200cdf0e10cSrcweir         throw ERROR;
201cdf0e10cSrcweir     } else if (modType&TransliterationModules_IGNORE_MASK) {
202cdf0e10cSrcweir #define TransliterationModules_IGNORE_CASE_MASK (TransliterationModules_IGNORE_CASE | \
203cdf0e10cSrcweir                                                 TransliterationModules_IGNORE_WIDTH | \
204cdf0e10cSrcweir                                                 TransliterationModules_IGNORE_KANA)
205cdf0e10cSrcweir         sal_Int32 mask = ((modType&TransliterationModules_IGNORE_CASE_MASK) == modType) ?
206cdf0e10cSrcweir                 TransliterationModules_IGNORE_CASE_MASK : TransliterationModules_IGNORE_MASK;
207cdf0e10cSrcweir         for (sal_Int16 i = 0; TMlist[i].tm & mask; i++) {
208cdf0e10cSrcweir             if (modType & TMlist[i].tm)
209cdf0e10cSrcweir                 if (loadModuleByName(OUString::createFromAscii(TMlist[i].implName),
210cdf0e10cSrcweir                                                 bodyCascade[numCascade], rLocale))
211cdf0e10cSrcweir                     numCascade++;
212cdf0e10cSrcweir         }
213cdf0e10cSrcweir     } else if (modType&TransliterationModules_NON_IGNORE_MASK) {
214cdf0e10cSrcweir         for (sal_Int16 i = 0; TMlist[i].tm; i++) {
215cdf0e10cSrcweir             if (TMlist[i].tm == modType) {
216cdf0e10cSrcweir                 if (loadModuleByName(OUString::createFromAscii(TMlist[i].implName), bodyCascade[numCascade], rLocale))
217cdf0e10cSrcweir                     numCascade++;
218cdf0e10cSrcweir                 break;
219cdf0e10cSrcweir             }
220cdf0e10cSrcweir         }
221cdf0e10cSrcweir     }
222cdf0e10cSrcweir }
223cdf0e10cSrcweir 
224cdf0e10cSrcweir void SAL_CALL
225cdf0e10cSrcweir TransliterationImpl::loadModuleNew( const Sequence < TransliterationModulesNew > & modType, const Locale& rLocale )
226cdf0e10cSrcweir   throw(RuntimeException)
227cdf0e10cSrcweir {
228cdf0e10cSrcweir     clear();
229cdf0e10cSrcweir     sal_Int32 mask = 0, count = modType.getLength();
230cdf0e10cSrcweir     if (count > maxCascade)
231cdf0e10cSrcweir         throw ERROR; // could not handle more than maxCascade
232cdf0e10cSrcweir     for (sal_Int16 i = 0; i < count; i++) {
233cdf0e10cSrcweir         for (sal_Int16 j = 0; TMlist[j].tmn; j++) {
234cdf0e10cSrcweir             if (TMlist[j].tmn == modType[i]) {
235cdf0e10cSrcweir                 if (mask == 0)
236cdf0e10cSrcweir                     mask = TMlist[i].tm && (TMlist[i].tm&TransliterationModules_IGNORE_MASK) ?
237cdf0e10cSrcweir                         TransliterationModules_IGNORE_MASK : TransliterationModules_NON_IGNORE_MASK;
238cdf0e10cSrcweir                 else if (mask == TransliterationModules_IGNORE_MASK &&
239cdf0e10cSrcweir                         (TMlist[i].tm&TransliterationModules_IGNORE_MASK) == 0)
240cdf0e10cSrcweir                     throw ERROR; // could not mess up ignore trans. with non_ignore trans.
241cdf0e10cSrcweir                 if (loadModuleByName(OUString::createFromAscii(TMlist[j].implName), bodyCascade[numCascade], rLocale))
242cdf0e10cSrcweir                     numCascade++;
243cdf0e10cSrcweir                 break;
244cdf0e10cSrcweir             }
245cdf0e10cSrcweir         }
246cdf0e10cSrcweir     }
247cdf0e10cSrcweir }
248cdf0e10cSrcweir 
249cdf0e10cSrcweir void SAL_CALL
250cdf0e10cSrcweir TransliterationImpl::loadModuleByImplName(const OUString& implName, const Locale& rLocale)
251cdf0e10cSrcweir   throw(RuntimeException)
252cdf0e10cSrcweir {
253cdf0e10cSrcweir     clear();
254cdf0e10cSrcweir     if (loadModuleByName(implName, bodyCascade[numCascade], rLocale))
255cdf0e10cSrcweir         numCascade++;
256cdf0e10cSrcweir }
257cdf0e10cSrcweir 
258cdf0e10cSrcweir 
259cdf0e10cSrcweir void SAL_CALL
260cdf0e10cSrcweir TransliterationImpl::loadModulesByImplNames(const Sequence< OUString >& implNameList, const Locale& rLocale ) throw(RuntimeException)
261cdf0e10cSrcweir {
262cdf0e10cSrcweir     if (implNameList.getLength() > maxCascade || implNameList.getLength() <= 0)
263cdf0e10cSrcweir         throw ERROR;
264cdf0e10cSrcweir 
265cdf0e10cSrcweir     clear();
266cdf0e10cSrcweir     for (sal_Int32 i = 0; i < implNameList.getLength(); i++)
267cdf0e10cSrcweir         if (loadModuleByName(implNameList[i], bodyCascade[numCascade], rLocale))
268cdf0e10cSrcweir             numCascade++;
269cdf0e10cSrcweir }
270cdf0e10cSrcweir 
271cdf0e10cSrcweir 
272cdf0e10cSrcweir Sequence<OUString> SAL_CALL
273cdf0e10cSrcweir TransliterationImpl::getAvailableModules( const Locale& rLocale, sal_Int16 sType ) throw(RuntimeException)
274cdf0e10cSrcweir {
275cdf0e10cSrcweir     const Sequence<OUString> &translist = localedata->getTransliterations(rLocale);
276cdf0e10cSrcweir     Sequence<OUString> r(translist.getLength());
277cdf0e10cSrcweir     Reference<XExtendedTransliteration> body;
278cdf0e10cSrcweir     sal_Int32 n = 0;
279cdf0e10cSrcweir     for (sal_Int32 i = 0; i < translist.getLength(); i++)
280cdf0e10cSrcweir     {
281cdf0e10cSrcweir         if (loadModuleByName(translist[i], body, rLocale)) {
282cdf0e10cSrcweir             if (body->getType() & sType)
283cdf0e10cSrcweir                 r[n++] = translist[i];
284cdf0e10cSrcweir             body.clear();
285cdf0e10cSrcweir         }
286cdf0e10cSrcweir     }
287cdf0e10cSrcweir     r.realloc(n);
288cdf0e10cSrcweir     return (r);
289cdf0e10cSrcweir }
290cdf0e10cSrcweir 
291cdf0e10cSrcweir 
292cdf0e10cSrcweir OUString SAL_CALL
293cdf0e10cSrcweir TransliterationImpl::transliterate( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
294cdf0e10cSrcweir                     Sequence< sal_Int32 >& offset ) throw(RuntimeException)
295cdf0e10cSrcweir {
296cdf0e10cSrcweir     if (numCascade == 0)
297cdf0e10cSrcweir         return inStr;
298cdf0e10cSrcweir 
299cdf0e10cSrcweir     if (offset.getLength() != nCount)
300cdf0e10cSrcweir         offset.realloc(nCount);
301cdf0e10cSrcweir     if (numCascade == 1)
302cdf0e10cSrcweir     {
303cdf0e10cSrcweir         if ( startPos == 0 && nCount == inStr.getLength() )
304cdf0e10cSrcweir             return bodyCascade[0]->transliterate( inStr, 0, nCount, offset);
305cdf0e10cSrcweir         else
306cdf0e10cSrcweir         {
307cdf0e10cSrcweir             OUString tmpStr = inStr.copy(startPos, nCount);
308cdf0e10cSrcweir             tmpStr = bodyCascade[0]->transliterate(tmpStr, 0, nCount, offset);
309cdf0e10cSrcweir             if ( startPos )
310cdf0e10cSrcweir             {
311cdf0e10cSrcweir                 sal_Int32 * pArr = offset.getArray();
312cdf0e10cSrcweir                 nCount = offset.getLength();
313cdf0e10cSrcweir                 for (sal_Int32 j = 0; j < nCount; j++)
314cdf0e10cSrcweir                     pArr[j] += startPos;
315cdf0e10cSrcweir             }
316cdf0e10cSrcweir             return tmpStr;
317cdf0e10cSrcweir         }
318cdf0e10cSrcweir     }
319cdf0e10cSrcweir     else
320cdf0e10cSrcweir     {
321cdf0e10cSrcweir         OUString tmpStr = inStr.copy(startPos, nCount);
322cdf0e10cSrcweir         sal_Int32 * pArr = offset.getArray();
323cdf0e10cSrcweir         for (sal_Int32 j = 0; j < nCount; j++)
324cdf0e10cSrcweir             pArr[j] = startPos + j;
325cdf0e10cSrcweir 
326cdf0e10cSrcweir         sal_Int16 from = 0, to = 1, tmp;
327cdf0e10cSrcweir         Sequence<sal_Int32> off[2];
328cdf0e10cSrcweir 
329cdf0e10cSrcweir         off[to] = offset;
330cdf0e10cSrcweir         off[from].realloc(nCount);
331cdf0e10cSrcweir         for (sal_Int32 i = 0; i < numCascade; i++) {
332cdf0e10cSrcweir             tmpStr = bodyCascade[i]->transliterate(tmpStr, 0, nCount, off[from]);
333cdf0e10cSrcweir 
334cdf0e10cSrcweir             nCount = tmpStr.getLength();
335cdf0e10cSrcweir 
336cdf0e10cSrcweir             tmp = from; from = to; to = tmp;
337cdf0e10cSrcweir             for (sal_Int32 j = 0; j < nCount; j++)
338cdf0e10cSrcweir                 off[to][j] = off[from][off[to][j]];
339cdf0e10cSrcweir         }
340cdf0e10cSrcweir         offset = off[to];
341cdf0e10cSrcweir         return tmpStr;
342cdf0e10cSrcweir     }
343cdf0e10cSrcweir }
344cdf0e10cSrcweir 
345cdf0e10cSrcweir 
346cdf0e10cSrcweir //
347cdf0e10cSrcweir OUString SAL_CALL
348cdf0e10cSrcweir TransliterationImpl::folding( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
349cdf0e10cSrcweir         Sequence< sal_Int32 >& offset ) throw(RuntimeException)
350cdf0e10cSrcweir {
351cdf0e10cSrcweir     if (numCascade == 0)
352cdf0e10cSrcweir         return inStr;
353cdf0e10cSrcweir 
354cdf0e10cSrcweir     if (offset.getLength() != nCount)
355cdf0e10cSrcweir         offset.realloc(nCount);
356cdf0e10cSrcweir     if (numCascade == 1)
357cdf0e10cSrcweir     {
358cdf0e10cSrcweir         if ( startPos == 0 && nCount == inStr.getLength() )
359cdf0e10cSrcweir             return bodyCascade[0]->folding( inStr, 0, nCount, offset);
360cdf0e10cSrcweir         else
361cdf0e10cSrcweir         {
362cdf0e10cSrcweir             OUString tmpStr = inStr.copy(startPos, nCount);
363cdf0e10cSrcweir             tmpStr = bodyCascade[0]->folding(tmpStr, 0, nCount, offset);
364cdf0e10cSrcweir             if ( startPos )
365cdf0e10cSrcweir             {
366cdf0e10cSrcweir                 sal_Int32 * pArr = offset.getArray();
367cdf0e10cSrcweir                 nCount = offset.getLength();
368cdf0e10cSrcweir                 for (sal_Int32 j = 0; j < nCount; j++)
369cdf0e10cSrcweir                     pArr[j] += startPos;
370cdf0e10cSrcweir             }
371cdf0e10cSrcweir             return tmpStr;
372cdf0e10cSrcweir         }
373cdf0e10cSrcweir     }
374cdf0e10cSrcweir     else
375cdf0e10cSrcweir     {
376cdf0e10cSrcweir         OUString tmpStr = inStr.copy(startPos, nCount);
377cdf0e10cSrcweir         sal_Int32 * pArr = offset.getArray();
378cdf0e10cSrcweir         for (sal_Int32 j = 0; j < nCount; j++)
379cdf0e10cSrcweir             pArr[j] = startPos + j;
380cdf0e10cSrcweir 
381cdf0e10cSrcweir         sal_Int16 from = 0, to = 1, tmp;
382cdf0e10cSrcweir         Sequence<sal_Int32> off[2];
383cdf0e10cSrcweir 
384cdf0e10cSrcweir         off[to] = offset;
385cdf0e10cSrcweir         for (sal_Int32 i = 0; i < numCascade; i++) {
386cdf0e10cSrcweir             tmpStr = bodyCascade[i]->folding(tmpStr, 0, nCount, off[from]);
387cdf0e10cSrcweir 
388cdf0e10cSrcweir             nCount = tmpStr.getLength();
389cdf0e10cSrcweir 
390cdf0e10cSrcweir             tmp = from; from = to; to = tmp;
391cdf0e10cSrcweir             for (sal_Int32 j = 0; j < nCount; j++)
392cdf0e10cSrcweir                 off[to][j] = off[from][off[to][j]];
393cdf0e10cSrcweir         }
394cdf0e10cSrcweir         offset = off[to];
395cdf0e10cSrcweir         return tmpStr;
396cdf0e10cSrcweir     }
397cdf0e10cSrcweir }
398cdf0e10cSrcweir 
399cdf0e10cSrcweir OUString SAL_CALL
400cdf0e10cSrcweir TransliterationImpl::transliterateString2String( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount ) throw(RuntimeException)
401cdf0e10cSrcweir {
402cdf0e10cSrcweir     if (numCascade == 0)
403cdf0e10cSrcweir         return inStr;
404cdf0e10cSrcweir     else if (numCascade == 1)
405cdf0e10cSrcweir         return bodyCascade[0]->transliterateString2String( inStr, startPos, nCount);
406cdf0e10cSrcweir     else {
407cdf0e10cSrcweir         OUString tmpStr = bodyCascade[0]->transliterateString2String(inStr, startPos, nCount);
408cdf0e10cSrcweir 
409cdf0e10cSrcweir         for (sal_Int32 i = 1; i < numCascade; i++)
410cdf0e10cSrcweir             tmpStr = bodyCascade[i]->transliterateString2String(tmpStr, 0, tmpStr.getLength());
411cdf0e10cSrcweir         return tmpStr;
412cdf0e10cSrcweir     }
413cdf0e10cSrcweir }
414cdf0e10cSrcweir 
415cdf0e10cSrcweir OUString SAL_CALL
416cdf0e10cSrcweir TransliterationImpl::transliterateChar2String( sal_Unicode inChar ) throw(RuntimeException)
417cdf0e10cSrcweir {
418cdf0e10cSrcweir     if (numCascade == 0)
419cdf0e10cSrcweir         return OUString(&inChar, 1);
420cdf0e10cSrcweir     else if (numCascade == 1)
421cdf0e10cSrcweir         return bodyCascade[0]->transliterateChar2String( inChar);
422cdf0e10cSrcweir     else {
423cdf0e10cSrcweir         OUString tmpStr = bodyCascade[0]->transliterateChar2String(inChar);
424cdf0e10cSrcweir 
425cdf0e10cSrcweir         for (sal_Int32 i = 1; i < numCascade; i++)
426cdf0e10cSrcweir             tmpStr = bodyCascade[i]->transliterateString2String(tmpStr, 0, tmpStr.getLength());
427cdf0e10cSrcweir         return tmpStr;
428cdf0e10cSrcweir     }
429cdf0e10cSrcweir }
430cdf0e10cSrcweir 
431cdf0e10cSrcweir sal_Unicode SAL_CALL
432cdf0e10cSrcweir TransliterationImpl::transliterateChar2Char( sal_Unicode inChar ) throw(MultipleCharsOutputException, RuntimeException)
433cdf0e10cSrcweir {
434cdf0e10cSrcweir     sal_Unicode tmpChar = inChar;
435cdf0e10cSrcweir     for (sal_Int32 i = 0; i < numCascade; i++)
436cdf0e10cSrcweir         tmpChar = bodyCascade[i]->transliterateChar2Char(tmpChar);
437cdf0e10cSrcweir     return tmpChar;
438cdf0e10cSrcweir }
439cdf0e10cSrcweir 
440cdf0e10cSrcweir 
441cdf0e10cSrcweir sal_Bool SAL_CALL
442cdf0e10cSrcweir TransliterationImpl::equals(
443cdf0e10cSrcweir     const OUString& str1, sal_Int32 pos1, sal_Int32 nCount1, sal_Int32& nMatch1,
444cdf0e10cSrcweir     const OUString& str2, sal_Int32 pos2, sal_Int32 nCount2, sal_Int32& nMatch2)
445cdf0e10cSrcweir     throw(RuntimeException)
446cdf0e10cSrcweir {
447cdf0e10cSrcweir     // since this is an API function make it user fail safe
448cdf0e10cSrcweir     if ( nCount1 < 0 ) {
449cdf0e10cSrcweir         pos1 += nCount1;
450cdf0e10cSrcweir         nCount1 = -nCount1;
451cdf0e10cSrcweir     }
452cdf0e10cSrcweir     if ( nCount2 < 0 ) {
453cdf0e10cSrcweir         pos2 += nCount2;
454cdf0e10cSrcweir         nCount2 = -nCount2;
455cdf0e10cSrcweir     }
456cdf0e10cSrcweir     if ( !nCount1 || !nCount2 ||
457cdf0e10cSrcweir             pos1 >= str1.getLength() || pos2 >= str2.getLength() ||
458cdf0e10cSrcweir             pos1 < 0 || pos2 < 0 ) {
459cdf0e10cSrcweir         nMatch1 = nMatch2 = 0;
460cdf0e10cSrcweir         // two empty strings return true, else false
461cdf0e10cSrcweir         return !nCount1 && !nCount2 && pos1 == str1.getLength() && pos2 == str2.getLength();
462cdf0e10cSrcweir     }
463cdf0e10cSrcweir     if ( pos1 + nCount1 > str1.getLength() )
464cdf0e10cSrcweir         nCount1 = str1.getLength() - pos1;
465cdf0e10cSrcweir     if ( pos2 + nCount2 > str2.getLength() )
466cdf0e10cSrcweir         nCount2 = str2.getLength() - pos2;
467cdf0e10cSrcweir 
468cdf0e10cSrcweir     if (caseignoreOnly && caseignore.is())
469cdf0e10cSrcweir         return caseignore->equals(str1, pos1, nCount1, nMatch1, str2, pos2, nCount2, nMatch2);
470cdf0e10cSrcweir 
471cdf0e10cSrcweir     Sequence<sal_Int32> offset1, offset2;
472cdf0e10cSrcweir 
473cdf0e10cSrcweir     OUString tmpStr1 = folding(str1, pos1, nCount1, offset1);
474cdf0e10cSrcweir     OUString tmpStr2 = folding(str2, pos2, nCount2, offset2);
475cdf0e10cSrcweir     // Length of offset1 and offset2 may still be 0 if there was no folding
476cdf0e10cSrcweir     // necessary!
477cdf0e10cSrcweir 
478cdf0e10cSrcweir     const sal_Unicode *p1 = tmpStr1.getStr();
479cdf0e10cSrcweir     const sal_Unicode *p2 = tmpStr2.getStr();
480cdf0e10cSrcweir     sal_Int32 i, nLen = ::std::min( tmpStr1.getLength(), tmpStr2.getLength());
481cdf0e10cSrcweir     for (i = 0; i < nLen; ++i, ++p1, ++p2 ) {
482cdf0e10cSrcweir         if (*p1 != *p2) {
483cdf0e10cSrcweir             // return number of matched code points so far
484cdf0e10cSrcweir             nMatch1 = (i < offset1.getLength()) ? offset1[i] : i;
485cdf0e10cSrcweir             nMatch2 = (i < offset2.getLength()) ? offset2[i] : i;
486cdf0e10cSrcweir             return sal_False;
487cdf0e10cSrcweir         }
488cdf0e10cSrcweir     }
489cdf0e10cSrcweir     // i==nLen
490cdf0e10cSrcweir     if ( tmpStr1.getLength() != tmpStr2.getLength() ) {
491cdf0e10cSrcweir         // return number of matched code points so far
492cdf0e10cSrcweir         nMatch1 = (i <= offset1.getLength()) ? offset1[i-1] + 1 : i;
493cdf0e10cSrcweir         nMatch2 = (i <= offset2.getLength()) ? offset2[i-1] + 1 : i;
494cdf0e10cSrcweir         return sal_False;
495cdf0e10cSrcweir     } else {
496cdf0e10cSrcweir         nMatch1 = nCount1;
497cdf0e10cSrcweir         nMatch2 = nCount2;
498cdf0e10cSrcweir         return sal_True;
499cdf0e10cSrcweir     }
500cdf0e10cSrcweir }
501cdf0e10cSrcweir 
502cdf0e10cSrcweir #define MaxOutput 2
503cdf0e10cSrcweir 
504cdf0e10cSrcweir Sequence< OUString > SAL_CALL
505cdf0e10cSrcweir TransliterationImpl::getRange(const Sequence< OUString > &inStrs,
506cdf0e10cSrcweir                 const sal_Int32 length, sal_Int16 _numCascade) throw(RuntimeException)
507cdf0e10cSrcweir {
508cdf0e10cSrcweir     if (_numCascade >= numCascade || ! bodyCascade[_numCascade].is())
509cdf0e10cSrcweir         return inStrs;
510cdf0e10cSrcweir 
511cdf0e10cSrcweir     sal_Int32 j_tmp = 0;
512cdf0e10cSrcweir     Sequence< OUString > ostr(MaxOutput*length);
513cdf0e10cSrcweir     for (sal_Int32 j = 0; j < length; j+=2) {
514cdf0e10cSrcweir         const Sequence< OUString >& temp = bodyCascade[_numCascade]->transliterateRange(inStrs[j], inStrs[j+1]);
515cdf0e10cSrcweir 
516cdf0e10cSrcweir         for ( sal_Int32 k = 0; k < temp.getLength(); k++) {
517cdf0e10cSrcweir             if ( j_tmp >= MaxOutput*length ) throw ERROR;
518cdf0e10cSrcweir             ostr[j_tmp++]  = temp[k];
519cdf0e10cSrcweir         }
520cdf0e10cSrcweir     }
521cdf0e10cSrcweir     ostr.realloc(j_tmp);
522cdf0e10cSrcweir 
523cdf0e10cSrcweir     return this->getRange(ostr, j_tmp, ++_numCascade);
524cdf0e10cSrcweir }
525cdf0e10cSrcweir 
526cdf0e10cSrcweir 
527cdf0e10cSrcweir Sequence< OUString > SAL_CALL
528cdf0e10cSrcweir TransliterationImpl::transliterateRange( const OUString& str1, const OUString& str2 )
529cdf0e10cSrcweir throw(RuntimeException)
530cdf0e10cSrcweir {
531cdf0e10cSrcweir     if (numCascade == 1)
532cdf0e10cSrcweir         return bodyCascade[0]->transliterateRange(str1, str2);
533cdf0e10cSrcweir 
534cdf0e10cSrcweir     Sequence< OUString > ostr(2);
535cdf0e10cSrcweir     ostr[0] = str1;
536cdf0e10cSrcweir     ostr[1] = str2;
537cdf0e10cSrcweir 
538cdf0e10cSrcweir     return this->getRange(ostr, 2, 0);
539cdf0e10cSrcweir }
540cdf0e10cSrcweir 
541cdf0e10cSrcweir 
542cdf0e10cSrcweir sal_Int32 SAL_CALL
543cdf0e10cSrcweir TransliterationImpl::compareSubstring(
544cdf0e10cSrcweir     const OUString& str1, sal_Int32 off1, sal_Int32 len1,
545cdf0e10cSrcweir     const OUString& str2, sal_Int32 off2, sal_Int32 len2)
546cdf0e10cSrcweir     throw(RuntimeException)
547cdf0e10cSrcweir {
548cdf0e10cSrcweir     if (caseignoreOnly && caseignore.is())
549cdf0e10cSrcweir         return caseignore->compareSubstring(str1, off1, len1, str2, off2, len2);
550cdf0e10cSrcweir 
551cdf0e10cSrcweir     Sequence <sal_Int32> offset;
552cdf0e10cSrcweir 
553cdf0e10cSrcweir     OUString in_str1 = this->transliterate(str1, off1, len1, offset);
554cdf0e10cSrcweir     OUString in_str2 = this->transliterate(str2, off2, len2, offset);
555cdf0e10cSrcweir     const sal_Unicode* unistr1 = in_str1.getStr();
556cdf0e10cSrcweir     const sal_Unicode* unistr2 = in_str2.getStr();
557cdf0e10cSrcweir     sal_Int32 strlen1 = in_str1.getLength();
558cdf0e10cSrcweir     sal_Int32 strlen2 = in_str2.getLength();
559cdf0e10cSrcweir 
560cdf0e10cSrcweir     while (strlen1 && strlen2) {
561cdf0e10cSrcweir         if (*unistr1 != *unistr2)
562cdf0e10cSrcweir            return *unistr1 > *unistr2 ? 1 : -1;
563cdf0e10cSrcweir 
564cdf0e10cSrcweir         unistr1++; unistr2++; strlen1--; strlen2--;
565cdf0e10cSrcweir     }
566cdf0e10cSrcweir     return strlen1 == strlen2 ? 0 : (strlen1 > strlen2 ? 1 : -1);
567cdf0e10cSrcweir }
568cdf0e10cSrcweir 
569cdf0e10cSrcweir 
570cdf0e10cSrcweir sal_Int32 SAL_CALL
571cdf0e10cSrcweir TransliterationImpl::compareString(const OUString& str1, const OUString& str2 ) throw (RuntimeException)
572cdf0e10cSrcweir {
573cdf0e10cSrcweir     if (caseignoreOnly && caseignore.is())
574cdf0e10cSrcweir         return caseignore->compareString(str1, str2);
575cdf0e10cSrcweir     else
576cdf0e10cSrcweir         return this->compareSubstring(str1, 0, str1.getLength(), str2, 0, str2.getLength());
577cdf0e10cSrcweir }
578cdf0e10cSrcweir 
579cdf0e10cSrcweir 
580cdf0e10cSrcweir void
581cdf0e10cSrcweir TransliterationImpl::clear()
582cdf0e10cSrcweir {
583cdf0e10cSrcweir     for (sal_Int32 i = 0; i < numCascade; i++)
584cdf0e10cSrcweir         if (bodyCascade[i].is())
585cdf0e10cSrcweir             bodyCascade[i].clear();
586cdf0e10cSrcweir     numCascade = 0;
587cdf0e10cSrcweir     caseignore.clear();
588cdf0e10cSrcweir     caseignoreOnly = sal_True;
589cdf0e10cSrcweir }
590cdf0e10cSrcweir 
591cdf0e10cSrcweir void TransliterationImpl::loadBody( OUString &implName, Reference<XExtendedTransliteration>& body )
592cdf0e10cSrcweir     throw (RuntimeException)
593cdf0e10cSrcweir {
594cdf0e10cSrcweir     ::osl::MutexGuard guard(lastTransBody.mutex);
595cdf0e10cSrcweir 
596cdf0e10cSrcweir     if (implName.equals(lastTransBody.Name))
597cdf0e10cSrcweir     {
598cdf0e10cSrcweir         // Use the cached body instead of going through the expensive looping again.
599cdf0e10cSrcweir         body = lastTransBody.Body;
600cdf0e10cSrcweir         return;
601cdf0e10cSrcweir     }
602cdf0e10cSrcweir 
603cdf0e10cSrcweir     Reference< XContentEnumerationAccess > xEnumAccess( xSMgr, UNO_QUERY );
604cdf0e10cSrcweir     Reference< XEnumeration > xEnum(xEnumAccess->createContentEnumeration(
605cdf0e10cSrcweir                                     OUString::createFromAscii(TRLT_SERVICELNAME_L10N)));
606cdf0e10cSrcweir     if (xEnum.is()) {
607cdf0e10cSrcweir         while (xEnum->hasMoreElements()) {
608cdf0e10cSrcweir             Any a = xEnum->nextElement();
609cdf0e10cSrcweir             Reference< XServiceInfo > xsInfo;
610cdf0e10cSrcweir             if (a >>= xsInfo) {
611cdf0e10cSrcweir                 if (implName.equals(xsInfo->getImplementationName())) {
612cdf0e10cSrcweir                     Reference< XSingleServiceFactory > xFactory;
613cdf0e10cSrcweir                     if (a >>= xFactory) {
614cdf0e10cSrcweir                         Reference< XInterface > xI = xFactory->createInstance();
615cdf0e10cSrcweir                         if (xI.is()) {
616cdf0e10cSrcweir                             a = xI->queryInterface(::getCppuType((
617cdf0e10cSrcweir                                         const Reference<XExtendedTransliteration>*)0));
618cdf0e10cSrcweir                             a >>= body;
619cdf0e10cSrcweir                             lastTransBody.Name = implName;
620cdf0e10cSrcweir                             lastTransBody.Body = body;
621cdf0e10cSrcweir                             return;
622cdf0e10cSrcweir                         }
623cdf0e10cSrcweir                     }
624cdf0e10cSrcweir                 }
625cdf0e10cSrcweir             }
626cdf0e10cSrcweir         }
627cdf0e10cSrcweir     }
628cdf0e10cSrcweir     throw ERROR;
629cdf0e10cSrcweir }
630cdf0e10cSrcweir 
631cdf0e10cSrcweir sal_Bool SAL_CALL
632cdf0e10cSrcweir TransliterationImpl::loadModuleByName( const OUString& implName,
633cdf0e10cSrcweir         Reference<XExtendedTransliteration>& body, const Locale& rLocale) throw(RuntimeException)
634cdf0e10cSrcweir {
635cdf0e10cSrcweir     OUString cname = OUString::createFromAscii(TRLT_IMPLNAME_PREFIX) + implName;
636cdf0e10cSrcweir     loadBody(cname, body);
637cdf0e10cSrcweir     if (body.is()) {
638cdf0e10cSrcweir         body->loadModule((TransliterationModules)0, rLocale); // toUpper/toLoad need rLocale
639cdf0e10cSrcweir 
640cdf0e10cSrcweir         // if the module is ignore case/kana/width, load caseignore for equals/compareString mothed
641cdf0e10cSrcweir         for (sal_Int16 i = 0; i < 3; i++) {
642cdf0e10cSrcweir             if (implName.compareToAscii(TMlist[i].implName) == 0) {
643cdf0e10cSrcweir                 if (i == 0) // current module is caseignore
644cdf0e10cSrcweir                     body->loadModule(TMlist[0].tm, rLocale); // caseingore need to setup module name
645cdf0e10cSrcweir                 if (! caseignore.is()) {
646cdf0e10cSrcweir                     OUString bname = OUString::createFromAscii(TRLT_IMPLNAME_PREFIX) +
647cdf0e10cSrcweir                                 OUString::createFromAscii(TMlist[0].implName);
648cdf0e10cSrcweir                     loadBody(bname, caseignore);
649cdf0e10cSrcweir                 }
650cdf0e10cSrcweir                 if (caseignore.is())
651cdf0e10cSrcweir                     caseignore->loadModule(TMlist[i].tm, rLocale);
652cdf0e10cSrcweir                 return sal_True;
653cdf0e10cSrcweir             }
654cdf0e10cSrcweir         }
655cdf0e10cSrcweir         caseignoreOnly = sal_False; // has other module than just ignore case/kana/width
656cdf0e10cSrcweir     }
657cdf0e10cSrcweir     return body.is();
658cdf0e10cSrcweir }
659cdf0e10cSrcweir 
660cdf0e10cSrcweir const sal_Char cTrans[] = "com.sun.star.i18n.Transliteration";
661cdf0e10cSrcweir 
662cdf0e10cSrcweir OUString SAL_CALL
663cdf0e10cSrcweir TransliterationImpl::getImplementationName() throw( RuntimeException )
664cdf0e10cSrcweir {
665cdf0e10cSrcweir     return OUString::createFromAscii(cTrans);
666cdf0e10cSrcweir }
667cdf0e10cSrcweir 
668cdf0e10cSrcweir 
669cdf0e10cSrcweir sal_Bool SAL_CALL
670cdf0e10cSrcweir TransliterationImpl::supportsService(const OUString& rServiceName) throw( RuntimeException )
671cdf0e10cSrcweir {
672cdf0e10cSrcweir     return !rServiceName.compareToAscii(cTrans);
673cdf0e10cSrcweir }
674cdf0e10cSrcweir 
675cdf0e10cSrcweir Sequence< OUString > SAL_CALL
676cdf0e10cSrcweir TransliterationImpl::getSupportedServiceNames(void) throw( RuntimeException )
677cdf0e10cSrcweir {
678cdf0e10cSrcweir     Sequence< OUString > aRet(1);
679cdf0e10cSrcweir     aRet[0] = OUString::createFromAscii(cTrans);
680cdf0e10cSrcweir     return aRet;
681cdf0e10cSrcweir }
682cdf0e10cSrcweir 
683cdf0e10cSrcweir } } } }
684