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