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