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