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 <collatorImpl.hxx> 28 #include <com/sun/star/i18n/CollatorOptions.hpp> 29 #include <rtl/ustrbuf.hxx> 30 31 using namespace com::sun::star; 32 using namespace com::sun::star::lang; 33 using namespace com::sun::star::uno; 34 using namespace rtl; 35 36 namespace com { namespace sun { namespace star { namespace i18n { 37 38 CollatorImpl::CollatorImpl( const Reference < XMultiServiceFactory >& rxMSF ) : xMSF(rxMSF) 39 { 40 if ( rxMSF.is()) { 41 Reference < XInterface > xI = 42 xMSF->createInstance( OUString::createFromAscii("com.sun.star.i18n.LocaleData")); 43 if ( xI.is() ) 44 xI->queryInterface(::getCppuType((const Reference< XLocaleData>*)0)) >>= localedata; 45 } 46 cachedItem = NULL; 47 } 48 49 CollatorImpl::~CollatorImpl() 50 { 51 // Clear lookuptable 52 for (size_t l = 0; l < lookupTable.size(); l++) 53 delete lookupTable[l]; 54 lookupTable.clear(); 55 } 56 57 sal_Int32 SAL_CALL 58 CollatorImpl::compareSubstring( const OUString& str1, sal_Int32 off1, sal_Int32 len1, 59 const OUString& str2, sal_Int32 off2, sal_Int32 len2) throw(RuntimeException) 60 { 61 if (cachedItem) 62 return cachedItem->xC->compareSubstring(str1, off1, len1, str2, off2, len2); 63 64 sal_Unicode *unistr1 = (sal_Unicode*) str1.getStr() + off1; 65 sal_Unicode *unistr2 = (sal_Unicode*) str2.getStr() + off2; 66 for (int i = 0; i < len1 && i < len2; i++) 67 if (unistr1[i] != unistr2[i]) 68 return unistr1[i] < unistr2[i] ? -1 : 1; 69 return len1 == len2 ? 0 : (len1 < len2 ? -1 : 1); 70 } 71 72 sal_Int32 SAL_CALL 73 CollatorImpl::compareString( const OUString& in_str1, const OUString& in_str2) throw(RuntimeException) 74 { 75 if (cachedItem) 76 return cachedItem->xC->compareString(in_str1, in_str2); 77 78 return CollatorImpl::compareSubstring(in_str1, 0, in_str1.getLength(), in_str2, 0, in_str2.getLength()); 79 } 80 81 82 sal_Int32 SAL_CALL 83 CollatorImpl::loadDefaultCollator(const lang::Locale& rLocale, sal_Int32 collatorOptions) throw(RuntimeException) 84 { 85 const Sequence< Implementation > &imp = localedata->getCollatorImplementations(rLocale); 86 for (sal_Int16 i = 0; i < imp.getLength(); i++) 87 if (imp[i].isDefault) 88 return loadCollatorAlgorithm(imp[i].unoID, rLocale, collatorOptions); 89 90 throw RuntimeException(); // not default is defined 91 //return 0; 92 } 93 94 sal_Int32 SAL_CALL 95 CollatorImpl::loadCollatorAlgorithm(const OUString& impl, const lang::Locale& rLocale, sal_Int32 collatorOptions) 96 throw(RuntimeException) 97 { 98 if (! cachedItem || ! cachedItem->equals(rLocale, impl)) 99 loadCachedCollator(rLocale, impl); 100 101 if (cachedItem) 102 cachedItem->xC->loadCollatorAlgorithm(cachedItem->algorithm, nLocale = rLocale, collatorOptions); 103 else 104 throw RuntimeException(); // impl could not be loaded 105 106 return 0; 107 } 108 109 void SAL_CALL 110 CollatorImpl::loadCollatorAlgorithmWithEndUserOption(const OUString& impl, const lang::Locale& rLocale, 111 const Sequence< sal_Int32 >& collatorOptions) throw(RuntimeException) 112 { 113 sal_Int32 options = 0; 114 for (sal_Int32 i = 0; i < collatorOptions.getLength(); i++) 115 options |= collatorOptions[i]; 116 loadCollatorAlgorithm(impl, rLocale, options); 117 } 118 119 Sequence< OUString > SAL_CALL 120 CollatorImpl::listCollatorAlgorithms( const lang::Locale& rLocale ) throw(RuntimeException) 121 { 122 nLocale = rLocale; 123 const Sequence< Implementation > &imp = localedata->getCollatorImplementations(rLocale); 124 Sequence< OUString > list(imp.getLength()); 125 126 for (sal_Int32 i = 0; i < imp.getLength(); i++) { 127 //if the current algorithm is default and the position is not on the first one, then switch 128 if (imp[i].isDefault && i) { 129 list[i] = list[0]; 130 list[0] = imp[i].unoID; 131 } 132 else 133 list[i] = imp[i].unoID; 134 } 135 return list; 136 } 137 138 Sequence< sal_Int32 > SAL_CALL 139 CollatorImpl::listCollatorOptions( const OUString& /*collatorAlgorithmName*/ ) throw(RuntimeException) 140 { 141 Sequence< OUString > option_str = localedata->getCollationOptions(nLocale); 142 Sequence< sal_Int32 > option_int(option_str.getLength()); 143 144 for (sal_Int32 i = 0; i < option_str.getLength(); i++) 145 option_int[i] = 146 option_str[i].equalsAscii("IGNORE_CASE") ? CollatorOptions::CollatorOptions_IGNORE_CASE : 147 option_str[i].equalsAscii("IGNORE_KANA") ? CollatorOptions::CollatorOptions_IGNORE_KANA : 148 option_str[i].equalsAscii("IGNORE_WIDTH") ? CollatorOptions::CollatorOptions_IGNORE_WIDTH : 0; 149 150 return option_int; 151 } 152 153 sal_Bool SAL_CALL 154 CollatorImpl::createCollator(const lang::Locale& rLocale, const OUString& serviceName, const OUString& rSortAlgorithm) 155 throw(RuntimeException) 156 { 157 for (size_t l = 0; l < lookupTable.size(); l++) { 158 cachedItem = lookupTable[l]; 159 if (cachedItem->service.equals(serviceName)) {// cross locale sharing 160 lookupTable.push_back(cachedItem = new lookupTableItem(rLocale, rSortAlgorithm, serviceName, cachedItem->xC)); 161 return sal_True; 162 } 163 } 164 if (xMSF.is()) { 165 Reference < XInterface > xI = 166 xMSF->createInstance(OUString::createFromAscii("com.sun.star.i18n.Collator_") + serviceName); 167 168 if (xI.is()) { 169 Reference < XCollator > xC; 170 xI->queryInterface( getCppuType((const Reference< XCollator>*)0) ) >>= xC; 171 if (xC.is()) { 172 lookupTable.push_back(cachedItem = new lookupTableItem(rLocale, rSortAlgorithm, serviceName, xC)); 173 return sal_True; 174 } 175 } 176 return sal_False; 177 } 178 throw RuntimeException(); 179 } 180 181 void SAL_CALL 182 CollatorImpl::loadCachedCollator(const lang::Locale& rLocale, const OUString& rSortAlgorithm) 183 throw(RuntimeException) 184 { 185 for (size_t i = 0; i < lookupTable.size(); i++) { 186 cachedItem = lookupTable[i]; 187 if (cachedItem->equals(rLocale, rSortAlgorithm)) { 188 return; 189 } 190 } 191 192 static sal_Unicode under = (sal_Unicode) '_'; 193 static OUString tw(OUString::createFromAscii("TW")); 194 static OUString unicode(OUString::createFromAscii("Unicode")); 195 196 sal_Int32 l = rLocale.Language.getLength(); 197 sal_Int32 c = rLocale.Country.getLength(); 198 sal_Int32 v = rLocale.Variant.getLength(); 199 sal_Int32 a = rSortAlgorithm.getLength(); 200 OUStringBuffer aBuf(l+c+v+a+4); 201 202 if ((l > 0 && c > 0 && v > 0 && a > 0 && 203 // load service with name <base>_<lang>_<country>_<varian>_<algorithm> 204 createCollator(rLocale, aBuf.append(rLocale.Language).append(under).append(rLocale.Country).append( 205 under).append(rLocale.Variant).append(under).append(rSortAlgorithm).makeStringAndClear(), 206 rSortAlgorithm)) || 207 (l > 0 && c > 0 && a > 0 && 208 // load service with name <base>_<lang>_<country>_<algorithm> 209 createCollator(rLocale, aBuf.append(rLocale.Language).append(under).append(rLocale.Country).append( 210 under).append(rSortAlgorithm).makeStringAndClear(), rSortAlgorithm)) || 211 (l > 0 && c > 0 && a > 0 && rLocale.Language.equalsAscii("zh") && 212 (rLocale.Country.equalsAscii("HK") || 213 rLocale.Country.equalsAscii("MO")) && 214 // if the country code is HK or MO, one more step to try TW. 215 createCollator(rLocale, aBuf.append(rLocale.Language).append(under).append(tw).append(under).append( 216 rSortAlgorithm).makeStringAndClear(), rSortAlgorithm)) || 217 (l > 0 && a > 0 && 218 // load service with name <base>_<lang>_<algorithm> 219 createCollator(rLocale, aBuf.append(rLocale.Language).append(under).append(rSortAlgorithm).makeStringAndClear(), 220 rSortAlgorithm)) || 221 // load service with name <base>_<algorithm> 222 (a > 0 && 223 createCollator(rLocale, rSortAlgorithm, rSortAlgorithm)) || 224 // load default service with name <base>_Unicode 225 createCollator(rLocale, unicode, rSortAlgorithm)) { 226 return; 227 } else { 228 cachedItem = NULL; 229 throw RuntimeException(); // could not load any service 230 } 231 } 232 233 const sal_Char cCollator[] = "com.sun.star.i18n.Collator"; 234 235 OUString SAL_CALL 236 CollatorImpl::getImplementationName() throw( RuntimeException ) 237 { 238 return OUString::createFromAscii(cCollator); 239 } 240 241 sal_Bool SAL_CALL 242 CollatorImpl::supportsService(const OUString& rServiceName) 243 throw( RuntimeException ) 244 { 245 return rServiceName.equalsAscii(cCollator); 246 } 247 248 Sequence< OUString > SAL_CALL 249 CollatorImpl::getSupportedServiceNames() throw( RuntimeException ) 250 { 251 Sequence< OUString > aRet(1); 252 aRet[0] = OUString::createFromAscii(cCollator); 253 return aRet; 254 } 255 256 } } } } 257