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 <assert.h>
22 : #include <textconversion.hxx>
23 : #include <com/sun/star/i18n/TextConversionType.hpp>
24 : #include <com/sun/star/i18n/TextConversionOption.hpp>
25 : #include <com/sun/star/linguistic2/ConversionDirection.hpp>
26 : #include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
27 : #include <com/sun/star/linguistic2/ConversionDictionaryList.hpp>
28 : #include <comphelper/string.hxx>
29 :
30 : using namespace com::sun::star::lang;
31 : using namespace com::sun::star::i18n;
32 : using namespace com::sun::star::linguistic2;
33 : using namespace com::sun::star::uno;
34 :
35 :
36 : namespace com { namespace sun { namespace star { namespace i18n {
37 :
38 0 : TextConversion_zh::TextConversion_zh( const Reference < XComponentContext >& xContext )
39 0 : : TextConversion("com.sun.star.i18n.TextConversion_zh")
40 : {
41 0 : xCDL = ConversionDictionaryList::create(xContext);
42 0 : }
43 :
44 0 : sal_Unicode SAL_CALL getOneCharConversion(sal_Unicode ch, const sal_Unicode* Data, const sal_uInt16* Index)
45 : {
46 0 : if (Data && Index) {
47 0 : sal_Unicode address = Index[ch>>8];
48 0 : if (address != 0xFFFF)
49 0 : address = Data[address + (ch & 0xFF)];
50 0 : return (address != 0xFFFF) ? address : ch;
51 : } else {
52 0 : return ch;
53 : }
54 : }
55 :
56 : #ifdef DISABLE_DYNLOADING
57 :
58 : extern "C" {
59 :
60 : const sal_Unicode* getSTC_CharData_T2S();
61 : const sal_uInt16* getSTC_CharIndex_T2S();
62 : const sal_Unicode* getSTC_CharData_S2V();
63 : const sal_uInt16* getSTC_CharIndex_S2V();
64 : const sal_Unicode* getSTC_CharData_S2T();
65 : const sal_uInt16* getSTC_CharIndex_S2T();
66 :
67 : const sal_Unicode *getSTC_WordData(sal_Int32&);
68 :
69 : const sal_uInt16 *getSTC_WordIndex_T2S(sal_Int32&);
70 : const sal_uInt16 *getSTC_WordEntry_T2S();
71 : const sal_uInt16 *getSTC_WordIndex_S2T(sal_Int32&);
72 : const sal_uInt16 *getSTC_WordEntry_S2T();
73 :
74 : }
75 :
76 : #endif
77 :
78 : OUString SAL_CALL
79 0 : TextConversion_zh::getCharConversion(const OUString& aText, sal_Int32 nStartPos, sal_Int32 nLength, sal_Bool toSChinese, sal_Int32 nConversionOptions)
80 : {
81 : const sal_Unicode *Data;
82 : const sal_uInt16 *Index;
83 :
84 : #ifndef DISABLE_DYNLOADING
85 0 : if (toSChinese) {
86 0 : Data = ((const sal_Unicode* (*)())getFunctionBySymbol("getSTC_CharData_T2S"))();
87 0 : Index = ((const sal_uInt16* (*)())getFunctionBySymbol("getSTC_CharIndex_T2S"))();
88 0 : } else if (nConversionOptions & TextConversionOption::USE_CHARACTER_VARIANTS) {
89 0 : Data = ((const sal_Unicode* (*)())getFunctionBySymbol("getSTC_CharData_S2V"))();
90 0 : Index = ((const sal_uInt16* (*)())getFunctionBySymbol("getSTC_CharIndex_S2V"))();
91 : } else {
92 0 : Data = ((const sal_Unicode* (*)())getFunctionBySymbol("getSTC_CharData_S2T"))();
93 0 : Index = ((const sal_uInt16* (*)())getFunctionBySymbol("getSTC_CharIndex_S2T"))();
94 : }
95 : #else
96 : if (toSChinese) {
97 : Data = getSTC_CharData_T2S();
98 : Index = getSTC_CharIndex_T2S();
99 : } else if (nConversionOptions & TextConversionOption::USE_CHARACTER_VARIANTS) {
100 : Data = getSTC_CharData_S2V();
101 : Index = getSTC_CharIndex_S2V();
102 : } else {
103 : Data = getSTC_CharData_S2T();
104 : Index = getSTC_CharIndex_S2T();
105 : }
106 : #endif
107 :
108 0 : rtl_uString * newStr = rtl_uString_alloc(nLength);
109 0 : for (sal_Int32 i = 0; i < nLength; i++)
110 : newStr->buffer[i] =
111 0 : getOneCharConversion(aText[nStartPos+i], Data, Index);
112 0 : return OUString(newStr, SAL_NO_ACQUIRE); //take ownership
113 : }
114 :
115 : OUString SAL_CALL
116 0 : TextConversion_zh::getWordConversion(const OUString& aText, sal_Int32 nStartPos, sal_Int32 nLength, sal_Bool toSChinese, sal_Int32 nConversionOptions, Sequence<sal_Int32>& offset)
117 : {
118 0 : sal_Int32 dictLen = 0;
119 0 : sal_Int32 maxLen = 0;
120 : const sal_uInt16 *index;
121 : const sal_uInt16 *entry;
122 : const sal_Unicode *charData;
123 : const sal_uInt16 *charIndex;
124 0 : sal_Bool one2one=sal_True;
125 :
126 : #ifndef DISABLE_DYNLOADING
127 0 : const sal_Unicode *wordData = ((const sal_Unicode* (*)(sal_Int32&)) getFunctionBySymbol("getSTC_WordData"))(dictLen);
128 0 : if (toSChinese) {
129 0 : index = ((const sal_uInt16* (*)(sal_Int32&)) getFunctionBySymbol("getSTC_WordIndex_T2S"))(maxLen);
130 0 : entry = ((const sal_uInt16* (*)()) getFunctionBySymbol("getSTC_WordEntry_T2S"))();
131 0 : charData = ((const sal_Unicode* (*)()) getFunctionBySymbol("getSTC_CharData_T2S"))();
132 0 : charIndex = ((const sal_uInt16* (*)()) getFunctionBySymbol("getSTC_CharIndex_T2S"))();
133 : } else {
134 0 : index = ((const sal_uInt16* (*)(sal_Int32&)) getFunctionBySymbol("getSTC_WordIndex_S2T"))(maxLen);
135 0 : entry = ((const sal_uInt16* (*)()) getFunctionBySymbol("getSTC_WordEntry_S2T"))();
136 0 : if (nConversionOptions & TextConversionOption::USE_CHARACTER_VARIANTS) {
137 0 : charData = ((const sal_Unicode* (*)()) getFunctionBySymbol("getSTC_CharData_S2V"))();
138 0 : charIndex = ((const sal_uInt16* (*)()) getFunctionBySymbol("getSTC_CharIndex_S2V"))();
139 : } else {
140 0 : charData = ((const sal_Unicode* (*)()) getFunctionBySymbol("getSTC_CharData_S2T"))();
141 0 : charIndex = ((const sal_uInt16* (*)()) getFunctionBySymbol("getSTC_CharIndex_S2T"))();
142 : }
143 : }
144 : #else
145 : const sal_Unicode *wordData = getSTC_WordData(dictLen);
146 : if (toSChinese) {
147 : index = getSTC_WordIndex_T2S(maxLen);
148 : entry = getSTC_WordEntry_T2S();
149 : charData = getSTC_CharData_T2S();
150 : charIndex = getSTC_CharIndex_T2S();
151 : } else {
152 : index = getSTC_WordIndex_S2T(maxLen);
153 : entry = getSTC_WordEntry_S2T();
154 : if (nConversionOptions & TextConversionOption::USE_CHARACTER_VARIANTS) {
155 : charData = getSTC_CharData_S2V();
156 : charIndex = getSTC_CharIndex_S2V();
157 : } else {
158 : charData = getSTC_CharData_S2T();
159 : charIndex = getSTC_CharIndex_S2T();
160 : }
161 : }
162 : #endif
163 :
164 0 : if ((!wordData || !index || !entry) && !xCDL.is()) // no word mapping defined, do char2char conversion.
165 0 : return getCharConversion(aText, nStartPos, nLength, toSChinese, nConversionOptions);
166 :
167 0 : sal_Unicode *newStr = new sal_Unicode[nLength * 2 + 1];
168 0 : sal_Int32 currPos = 0, count = 0;
169 0 : while (currPos < nLength) {
170 0 : sal_Int32 len = nLength - currPos;
171 0 : sal_Bool found = sal_False;
172 0 : if (len > maxLen)
173 0 : len = maxLen;
174 0 : for (; len > 0 && ! found; len--) {
175 0 : OUString word = aText.copy(nStartPos + currPos, len);
176 0 : sal_Int32 current = 0;
177 : // user dictionary
178 0 : if (xCDL.is()) {
179 0 : Sequence < OUString > conversions;
180 : try {
181 0 : conversions = xCDL->queryConversions(word, 0, len,
182 : aLocale, ConversionDictionaryType::SCHINESE_TCHINESE,
183 : /*toSChinese ?*/ ConversionDirection_FROM_LEFT /*: ConversionDirection_FROM_RIGHT*/,
184 0 : nConversionOptions);
185 : }
186 0 : catch ( NoSupportException & ) {
187 : // clear reference (when there is no user dictionary) in order
188 : // to not always have to catch this exception again
189 : // in further calls. (save time)
190 0 : xCDL = 0;
191 : }
192 0 : catch (...) {
193 : // catch all other exceptions to allow
194 : // querying the system dictionary in the next line
195 : }
196 0 : if (conversions.getLength() > 0) {
197 0 : if (offset.getLength() > 0) {
198 0 : if (word.getLength() != conversions[0].getLength())
199 0 : one2one=sal_False;
200 0 : while (current < conversions[0].getLength()) {
201 0 : offset[count] = nStartPos + currPos + (current *
202 0 : word.getLength() / conversions[0].getLength());
203 0 : newStr[count++] = conversions[0][current++];
204 : }
205 : // offset[count-1] = nStartPos + currPos + word.getLength() - 1;
206 : } else {
207 0 : while (current < conversions[0].getLength())
208 0 : newStr[count++] = conversions[0][current++];
209 : }
210 0 : currPos += word.getLength();
211 0 : found = sal_True;
212 0 : }
213 : }
214 :
215 0 : if (!found && index[len+1] - index[len] > 0) {
216 0 : sal_Int32 bottom = (sal_Int32) index[len];
217 0 : sal_Int32 top = (sal_Int32) index[len+1] - 1;
218 :
219 0 : while (bottom <= top && !found) {
220 0 : current = (top + bottom) / 2;
221 0 : const sal_Int32 result = word.compareTo(wordData + entry[current]);
222 0 : if (result < 0)
223 0 : top = current - 1;
224 0 : else if (result > 0)
225 0 : bottom = current + 1;
226 : else {
227 0 : if (toSChinese) // Traditionary/Simplified conversion,
228 0 : for (current = entry[current]-1; current > 0 && wordData[current-1]; current--) ;
229 : else // Simplified/Traditionary conversion, forwards search for next word
230 0 : current = entry[current] + word.getLength() + 1;
231 0 : sal_Int32 start=current;
232 0 : if (offset.getLength() > 0) {
233 0 : if (word.getLength() != OUString(&wordData[current]).getLength())
234 0 : one2one=sal_False;
235 0 : sal_Int32 convertedLength=OUString(&wordData[current]).getLength();
236 0 : while (wordData[current]) {
237 0 : offset[count]=nStartPos + currPos + ((current-start) *
238 0 : word.getLength() / convertedLength);
239 0 : newStr[count++] = wordData[current++];
240 : }
241 : // offset[count-1]=nStartPos + currPos + word.getLength() - 1;
242 : } else {
243 0 : while (wordData[current])
244 0 : newStr[count++] = wordData[current++];
245 : }
246 0 : currPos += word.getLength();
247 0 : found = sal_True;
248 : }
249 : }
250 : }
251 0 : }
252 0 : if (!found) {
253 0 : if (offset.getLength() > 0)
254 0 : offset[count]=nStartPos+currPos;
255 0 : newStr[count++] =
256 0 : getOneCharConversion(aText[nStartPos+currPos], charData, charIndex);
257 0 : currPos++;
258 : }
259 : }
260 0 : if (offset.getLength() > 0)
261 0 : offset.realloc(one2one ? 0 : count);
262 0 : OUString aRet(newStr, count);
263 0 : delete[] newStr;
264 0 : return aRet;
265 : }
266 :
267 : TextConversionResult SAL_CALL
268 0 : TextConversion_zh::getConversions( const OUString& aText, sal_Int32 nStartPos, sal_Int32 nLength,
269 : const Locale& rLocale, sal_Int16 nConversionType, sal_Int32 nConversionOptions)
270 : throw( RuntimeException, IllegalArgumentException, NoSupportException, std::exception )
271 : {
272 0 : TextConversionResult result;
273 :
274 0 : result.Candidates.realloc(1);
275 0 : result.Candidates[0] = getConversion( aText, nStartPos, nLength, rLocale, nConversionType, nConversionOptions);
276 0 : result.Boundary.startPos = nStartPos;
277 0 : result.Boundary.endPos = nStartPos + nLength;
278 :
279 0 : return result;
280 : }
281 :
282 : OUString SAL_CALL
283 0 : TextConversion_zh::getConversion( const OUString& aText, sal_Int32 nStartPos, sal_Int32 nLength,
284 : const Locale& rLocale, sal_Int16 nConversionType, sal_Int32 nConversionOptions)
285 : throw( RuntimeException, IllegalArgumentException, NoSupportException, std::exception )
286 : {
287 0 : if (rLocale.Language == "zh" && ( nConversionType == TextConversionType::TO_SCHINESE || nConversionType == TextConversionType::TO_TCHINESE) ) {
288 :
289 0 : aLocale=rLocale;
290 0 : sal_Bool toSChinese = nConversionType == TextConversionType::TO_SCHINESE;
291 :
292 0 : if (nConversionOptions & TextConversionOption::CHARACTER_BY_CHARACTER)
293 : // char to char dictionary
294 0 : return getCharConversion(aText, nStartPos, nLength, toSChinese, nConversionOptions);
295 : else {
296 0 : Sequence <sal_Int32> offset;
297 : // word to word dictionary
298 0 : return getWordConversion(aText, nStartPos, nLength, toSChinese, nConversionOptions, offset);
299 : }
300 : } else
301 0 : throw NoSupportException(); // Conversion type is not supported in this service.
302 : }
303 :
304 : OUString SAL_CALL
305 0 : TextConversion_zh::getConversionWithOffset( const OUString& aText, sal_Int32 nStartPos, sal_Int32 nLength,
306 : const Locale& rLocale, sal_Int16 nConversionType, sal_Int32 nConversionOptions, Sequence<sal_Int32>& offset)
307 : throw( RuntimeException, IllegalArgumentException, NoSupportException, std::exception )
308 : {
309 0 : if (rLocale.Language == "zh" && ( nConversionType == TextConversionType::TO_SCHINESE || nConversionType == TextConversionType::TO_TCHINESE) ) {
310 :
311 0 : aLocale=rLocale;
312 0 : sal_Bool toSChinese = nConversionType == TextConversionType::TO_SCHINESE;
313 :
314 0 : if (nConversionOptions & TextConversionOption::CHARACTER_BY_CHARACTER) {
315 0 : offset.realloc(0);
316 : // char to char dictionary
317 0 : return getCharConversion(aText, nStartPos, nLength, toSChinese, nConversionOptions);
318 : } else {
319 0 : if (offset.getLength() < 2*nLength)
320 0 : offset.realloc(2*nLength);
321 : // word to word dictionary
322 0 : return getWordConversion(aText, nStartPos, nLength, toSChinese, nConversionOptions, offset);
323 : }
324 : } else
325 0 : throw NoSupportException(); // Conversion type is not supported in this service.
326 : }
327 :
328 : sal_Bool SAL_CALL
329 0 : TextConversion_zh::interactiveConversion( const Locale& /*rLocale*/, sal_Int16 /*nTextConversionType*/, sal_Int32 /*nTextConversionOptions*/ )
330 : throw( RuntimeException, IllegalArgumentException, NoSupportException, std::exception )
331 : {
332 0 : return sal_False;
333 : }
334 :
335 : } } } }
336 :
337 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|