Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <collatorImpl.hxx>
22 : #include <com/sun/star/i18n/CollatorOptions.hpp>
23 : #include <com/sun/star/i18n/LocaleData.hpp>
24 : #include <rtl/ustrbuf.hxx>
25 : #include <comphelper/processfactory.hxx>
26 :
27 : using namespace com::sun::star;
28 : using namespace com::sun::star::lang;
29 : using namespace com::sun::star::uno;
30 :
31 : using ::rtl::OUString;
32 : using ::rtl::OUStringBuffer;
33 :
34 : namespace com { namespace sun { namespace star { namespace i18n {
35 :
36 8 : CollatorImpl::CollatorImpl( const Reference < XComponentContext >& rxContext ) : m_xContext(rxContext)
37 : {
38 8 : mxLocaleData.set( LocaleData::create(rxContext) );
39 8 : cachedItem = NULL;
40 8 : }
41 :
42 9 : CollatorImpl::~CollatorImpl()
43 : {
44 : // Clear lookuptable
45 6 : for (size_t l = 0; l < lookupTable.size(); l++)
46 3 : delete lookupTable[l];
47 3 : lookupTable.clear();
48 6 : }
49 :
50 : sal_Int32 SAL_CALL
51 0 : CollatorImpl::compareSubstring( const OUString& str1, sal_Int32 off1, sal_Int32 len1,
52 : const OUString& str2, sal_Int32 off2, sal_Int32 len2) throw(RuntimeException)
53 : {
54 0 : if (cachedItem)
55 0 : return cachedItem->xC->compareSubstring(str1, off1, len1, str2, off2, len2);
56 :
57 0 : sal_Unicode *unistr1 = (sal_Unicode*) str1.getStr() + off1;
58 0 : sal_Unicode *unistr2 = (sal_Unicode*) str2.getStr() + off2;
59 0 : for (int i = 0; i < len1 && i < len2; i++)
60 0 : if (unistr1[i] != unistr2[i])
61 0 : return unistr1[i] < unistr2[i] ? -1 : 1;
62 0 : return len1 == len2 ? 0 : (len1 < len2 ? -1 : 1);
63 : }
64 :
65 : sal_Int32 SAL_CALL
66 3339 : CollatorImpl::compareString( const OUString& in_str1, const OUString& in_str2) throw(RuntimeException)
67 : {
68 3339 : if (cachedItem)
69 3339 : return cachedItem->xC->compareString(in_str1, in_str2);
70 :
71 0 : return CollatorImpl::compareSubstring(in_str1, 0, in_str1.getLength(), in_str2, 0, in_str2.getLength());
72 : }
73 :
74 :
75 : sal_Int32 SAL_CALL
76 8 : CollatorImpl::loadDefaultCollator(const lang::Locale& rLocale, sal_Int32 collatorOptions) throw(RuntimeException)
77 : {
78 8 : const Sequence< Implementation > &imp = mxLocaleData->getCollatorImplementations(rLocale);
79 8 : for (sal_Int16 i = 0; i < imp.getLength(); i++)
80 8 : if (imp[i].isDefault)
81 16 : return loadCollatorAlgorithm(imp[i].unoID, rLocale, collatorOptions);
82 :
83 8 : throw RuntimeException(); // not default is defined
84 : //return 0;
85 : }
86 :
87 : sal_Int32 SAL_CALL
88 8 : CollatorImpl::loadCollatorAlgorithm(const OUString& impl, const lang::Locale& rLocale, sal_Int32 collatorOptions)
89 : throw(RuntimeException)
90 : {
91 8 : if (! cachedItem || ! cachedItem->equals(rLocale, impl))
92 8 : loadCachedCollator(rLocale, impl);
93 :
94 8 : if (cachedItem)
95 8 : cachedItem->xC->loadCollatorAlgorithm(cachedItem->algorithm, nLocale = rLocale, collatorOptions);
96 : else
97 0 : throw RuntimeException(); // impl could not be loaded
98 :
99 16 : return 0;
100 : }
101 :
102 : void SAL_CALL
103 0 : CollatorImpl::loadCollatorAlgorithmWithEndUserOption(const OUString& impl, const lang::Locale& rLocale,
104 : const Sequence< sal_Int32 >& collatorOptions) throw(RuntimeException)
105 : {
106 0 : sal_Int32 options = 0;
107 0 : for (sal_Int32 i = 0; i < collatorOptions.getLength(); i++)
108 0 : options |= collatorOptions[i];
109 0 : loadCollatorAlgorithm(impl, rLocale, options);
110 0 : }
111 :
112 : Sequence< OUString > SAL_CALL
113 0 : CollatorImpl::listCollatorAlgorithms( const lang::Locale& rLocale ) throw(RuntimeException)
114 : {
115 0 : nLocale = rLocale;
116 0 : const Sequence< Implementation > &imp = mxLocaleData->getCollatorImplementations(rLocale);
117 0 : Sequence< OUString > list(imp.getLength());
118 :
119 0 : for (sal_Int32 i = 0; i < imp.getLength(); i++) {
120 : //if the current algorithm is default and the position is not on the first one, then switch
121 0 : if (imp[i].isDefault && i) {
122 0 : list[i] = list[0];
123 0 : list[0] = imp[i].unoID;
124 : }
125 : else
126 0 : list[i] = imp[i].unoID;
127 : }
128 0 : return list;
129 : }
130 :
131 : Sequence< sal_Int32 > SAL_CALL
132 0 : CollatorImpl::listCollatorOptions( const OUString& /*collatorAlgorithmName*/ ) throw(RuntimeException)
133 : {
134 0 : Sequence< OUString > option_str = mxLocaleData->getCollationOptions(nLocale);
135 0 : Sequence< sal_Int32 > option_int(option_str.getLength());
136 :
137 0 : for (sal_Int32 i = 0; i < option_str.getLength(); i++)
138 0 : option_int[i] =
139 0 : option_str[i] == "IGNORE_CASE" ? CollatorOptions::CollatorOptions_IGNORE_CASE :
140 0 : option_str[i] == "IGNORE_KANA" ? CollatorOptions::CollatorOptions_IGNORE_KANA :
141 0 : option_str[i] == "IGNORE_WIDTH" ? CollatorOptions::CollatorOptions_IGNORE_WIDTH : 0;
142 :
143 0 : return option_int;
144 : }
145 :
146 : sal_Bool SAL_CALL
147 24 : CollatorImpl::createCollator(const lang::Locale& rLocale, const OUString& serviceName, const OUString& rSortAlgorithm)
148 : throw(RuntimeException)
149 : {
150 24 : for (size_t l = 0; l < lookupTable.size(); l++) {
151 0 : cachedItem = lookupTable[l];
152 0 : if (cachedItem->service.equals(serviceName)) {// cross locale sharing
153 0 : lookupTable.push_back(cachedItem = new lookupTableItem(rLocale, rSortAlgorithm, serviceName, cachedItem->xC));
154 0 : return sal_True;
155 : }
156 : }
157 : Reference < XInterface > xI =
158 24 : m_xContext->getServiceManager()->createInstanceWithContext( OUString("com.sun.star.i18n.Collator_") + serviceName, m_xContext );
159 :
160 24 : if (xI.is()) {
161 8 : Reference < XCollator > xC;
162 8 : xI->queryInterface( getCppuType((const Reference< XCollator>*)0) ) >>= xC;
163 8 : if (xC.is()) {
164 8 : lookupTable.push_back(cachedItem = new lookupTableItem(rLocale, rSortAlgorithm, serviceName, xC));
165 8 : return sal_True;
166 8 : }
167 : }
168 16 : return sal_False;
169 : }
170 :
171 : void SAL_CALL
172 8 : CollatorImpl::loadCachedCollator(const lang::Locale& rLocale, const OUString& rSortAlgorithm)
173 : throw(RuntimeException)
174 : {
175 8 : for (size_t i = 0; i < lookupTable.size(); i++) {
176 0 : cachedItem = lookupTable[i];
177 0 : if (cachedItem->equals(rLocale, rSortAlgorithm)) {
178 : return;
179 : }
180 : }
181 :
182 : static sal_Unicode under = (sal_Unicode) '_';
183 :
184 8 : sal_Int32 l = rLocale.Language.getLength();
185 8 : sal_Int32 c = rLocale.Country.getLength();
186 8 : sal_Int32 v = rLocale.Variant.getLength();
187 8 : sal_Int32 a = rSortAlgorithm.getLength();
188 8 : OUStringBuffer aBuf(l+c+v+a+4);
189 :
190 60 : if ((l > 0 && c > 0 && v > 0 && a > 0 &&
191 : // load service with name <base>_<lang>_<country>_<varian>_<algorithm>
192 0 : createCollator(rLocale, aBuf.append(rLocale.Language).append(under).append(rLocale.Country).append(
193 0 : under).append(rLocale.Variant).append(under).append(rSortAlgorithm).makeStringAndClear(),
194 8 : rSortAlgorithm)) ||
195 : (l > 0 && c > 0 && a > 0 &&
196 : // load service with name <base>_<lang>_<country>_<algorithm>
197 4 : createCollator(rLocale, aBuf.append(rLocale.Language).append(under).append(rLocale.Country).append(
198 20 : under).append(rSortAlgorithm).makeStringAndClear(), rSortAlgorithm)) ||
199 4 : (l > 0 && c > 0 && a > 0 && rLocale.Language == "zh" && (rLocale.Country == "HK" || rLocale.Country == "MO") &&
200 : // if the country code is HK or MO, one more step to try TW.
201 0 : createCollator(rLocale, aBuf.append(rLocale.Language).append(under).append("TW").append(under).append(
202 8 : rSortAlgorithm).makeStringAndClear(), rSortAlgorithm)) ||
203 : (l > 0 && a > 0 &&
204 : // load service with name <base>_<lang>_<algorithm>
205 4 : createCollator(rLocale, aBuf.append(rLocale.Language).append(under).append(rSortAlgorithm).makeStringAndClear(),
206 16 : rSortAlgorithm)) ||
207 : // load service with name <base>_<algorithm>
208 : (a > 0 &&
209 8 : createCollator(rLocale, rSortAlgorithm, rSortAlgorithm)) ||
210 : // load default service with name <base>_Unicode
211 24 : createCollator(rLocale, "Unicode", rSortAlgorithm)) {
212 : return;
213 : } else {
214 0 : cachedItem = NULL;
215 0 : throw RuntimeException(); // could not load any service
216 8 : }
217 : }
218 :
219 : const sal_Char cCollator[] = "com.sun.star.i18n.Collator";
220 :
221 : OUString SAL_CALL
222 0 : CollatorImpl::getImplementationName() throw( RuntimeException )
223 : {
224 0 : return OUString::createFromAscii(cCollator);
225 : }
226 :
227 : sal_Bool SAL_CALL
228 0 : CollatorImpl::supportsService(const OUString& rServiceName)
229 : throw( RuntimeException )
230 : {
231 0 : return rServiceName.equalsAscii(cCollator);
232 : }
233 :
234 : Sequence< OUString > SAL_CALL
235 0 : CollatorImpl::getSupportedServiceNames() throw( RuntimeException )
236 : {
237 0 : Sequence< OUString > aRet(1);
238 0 : aRet[0] = OUString::createFromAscii(cCollator);
239 0 : return aRet;
240 : }
241 :
242 : } } } }
243 :
244 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|