Branch data 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 : : #include <i18npool/mslangid.hxx>
21 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
22 : : #include <com/sun/star/util/TextSearch.hpp>
23 : : #include <com/sun/star/util/SearchFlags.hpp>
24 : : #include <com/sun/star/i18n/TransliterationModules.hpp>
25 : : #include <unotools/charclass.hxx>
26 : : #include <comphelper/processfactory.hxx>
27 : : #include <unotools/textsearch.hxx>
28 : : #include <rtl/instance.hxx>
29 : :
30 : : using namespace ::com::sun::star::util;
31 : : using namespace ::com::sun::star::uno;
32 : : using namespace ::com::sun::star::lang;
33 : :
34 : : // ............................................................................
35 : : namespace utl
36 : : {
37 : : // ............................................................................
38 : :
39 : 0 : SearchParam::SearchParam( const String &rText,
40 : : SearchType eType,
41 : : sal_Bool bCaseSensitive,
42 : : sal_Bool bWrdOnly,
43 [ # # ]: 0 : sal_Bool bSearchInSel )
44 : : {
45 [ # # ]: 0 : sSrchStr = rText;
46 : 0 : m_eSrchType = eType;
47 : :
48 : 0 : m_bWordOnly = bWrdOnly;
49 : 0 : m_bSrchInSel = bSearchInSel;
50 : 0 : m_bCaseSense = bCaseSensitive;
51 : :
52 : 0 : nTransliterationFlags = 0;
53 : :
54 : : // Parameters for weighted Levenshtein distance
55 : 0 : bLEV_Relaxed = sal_True;
56 : 0 : nLEV_OtherX = 2;
57 : 0 : nLEV_ShorterY = 1;
58 : 0 : nLEV_LongerZ = 3;
59 : 0 : }
60 : :
61 [ # # ]: 0 : SearchParam::SearchParam( const SearchParam& rParam )
62 : : {
63 [ # # ]: 0 : sSrchStr = rParam.sSrchStr;
64 [ # # ]: 0 : sReplaceStr = rParam.sReplaceStr;
65 : 0 : m_eSrchType = rParam.m_eSrchType;
66 : :
67 : 0 : m_bWordOnly = rParam.m_bWordOnly;
68 : 0 : m_bSrchInSel = rParam.m_bSrchInSel;
69 : 0 : m_bCaseSense = rParam.m_bCaseSense;
70 : :
71 : 0 : bLEV_Relaxed = rParam.bLEV_Relaxed;
72 : 0 : nLEV_OtherX = rParam.nLEV_OtherX;
73 : 0 : nLEV_ShorterY = rParam.nLEV_ShorterY;
74 : 0 : nLEV_LongerZ = rParam.nLEV_LongerZ;
75 : :
76 : 0 : nTransliterationFlags = rParam.nTransliterationFlags;
77 : 0 : }
78 : :
79 : 82 : static bool lcl_Equals( const SearchOptions& rSO1, const SearchOptions& rSO2 )
80 : : {
81 : : return rSO1.algorithmType == rSO2.algorithmType &&
82 : : rSO1.searchFlag == rSO2.searchFlag &&
83 : 79 : rSO1.searchString.equals(rSO2.searchString) &&
84 : 26 : rSO1.replaceString.equals(rSO2.replaceString) &&
85 : : rSO1.changedChars == rSO2.changedChars &&
86 : : rSO1.deletedChars == rSO2.deletedChars &&
87 : : rSO1.insertedChars == rSO2.insertedChars &&
88 : 21 : rSO1.Locale.Language == rSO2.Locale.Language &&
89 : 21 : rSO1.Locale.Country == rSO2.Locale.Country &&
90 : 21 : rSO1.Locale.Variant == rSO2.Locale.Variant &&
91 [ + - ][ + + : 250 : rSO1.transliterateFlags == rSO2.transliterateFlags;
+ + + + ]
[ + - ][ + - ]
[ + - + -
+ - + - ]
[ + - ]
92 : : }
93 : :
94 : : namespace
95 : : {
96 : 14 : struct CachedTextSearch
97 : : {
98 : : ::osl::Mutex mutex;
99 : : ::com::sun::star::util::SearchOptions Options;
100 : : ::com::sun::star::uno::Reference< ::com::sun::star::util::XTextSearch > xTextSearch;
101 : : };
102 : :
103 : : struct theCachedTextSearch
104 : : : public rtl::Static< CachedTextSearch, theCachedTextSearch > {};
105 : : }
106 : :
107 : 82 : Reference<XTextSearch> TextSearch::getXTextSearch( const SearchOptions& rPara )
108 : : {
109 [ + - ]: 82 : CachedTextSearch &rCache = theCachedTextSearch::get();
110 : :
111 [ + - ]: 82 : osl::MutexGuard aGuard(rCache.mutex);
112 : :
113 [ + + ]: 82 : if ( lcl_Equals(rCache.Options, rPara) )
114 : 21 : return rCache.xTextSearch;
115 : :
116 : : try
117 : : {
118 [ + - ]: 61 : Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
119 [ + - ][ + - ]: 61 : rCache.xTextSearch.set( ::TextSearch::create(xContext) );
120 [ + - ][ + - ]: 61 : rCache.xTextSearch->setOptions( rPara );
121 [ # # ]: 61 : rCache.Options = rPara;
122 : : }
123 [ # # ]: 0 : catch ( Exception& e )
124 : : {
125 : : SAL_WARN( "unotools.i18n", "caught " << e.Message );
126 : : }
127 [ + - ]: 82 : return rCache.xTextSearch;
128 : : }
129 : :
130 : 0 : TextSearch::TextSearch(const SearchParam & rParam, LanguageType eLang )
131 : : {
132 [ # # ]: 0 : if( LANGUAGE_NONE == eLang )
133 : 0 : eLang = LANGUAGE_SYSTEM;
134 : : ::com::sun::star::lang::Locale aLocale(
135 [ # # ]: 0 : MsLangId::convertLanguageToLocale( LanguageType(eLang)));
136 : :
137 [ # # ]: 0 : Init( rParam, aLocale);
138 : 0 : }
139 : :
140 : 0 : TextSearch::TextSearch(const SearchParam & rParam, const CharClass& rCClass )
141 : : {
142 [ # # ][ # # ]: 0 : Init( rParam, rCClass.getLocale() );
143 : 0 : }
144 : :
145 : 82 : TextSearch::TextSearch( const SearchOptions& rPara )
146 : : {
147 [ + - ][ + - ]: 82 : xTextSearch = getXTextSearch( rPara );
148 : 82 : }
149 : :
150 : 0 : void TextSearch::Init( const SearchParam & rParam,
151 : : const ::com::sun::star::lang::Locale& rLocale )
152 : : {
153 : : // convert SearchParam to the UNO SearchOptions
154 : 0 : SearchOptions aSOpt;
155 : :
156 [ # # # ]: 0 : switch( rParam.GetSrchType() )
157 : : {
158 : : case SearchParam::SRCH_REGEXP:
159 : 0 : aSOpt.algorithmType = SearchAlgorithms_REGEXP;
160 [ # # ]: 0 : if( rParam.IsSrchInSelection() )
161 : : aSOpt.searchFlag |= SearchFlags::REG_NOT_BEGINOFLINE |
162 : 0 : SearchFlags::REG_NOT_ENDOFLINE;
163 : 0 : break;
164 : :
165 : : case SearchParam::SRCH_LEVDIST:
166 : 0 : aSOpt.algorithmType = SearchAlgorithms_APPROXIMATE;
167 : 0 : aSOpt.changedChars = rParam.GetLEVOther();
168 : 0 : aSOpt.deletedChars = rParam.GetLEVLonger();
169 : 0 : aSOpt.insertedChars = rParam.GetLEVShorter();
170 [ # # ]: 0 : if( rParam.IsSrchRelaxed() )
171 : 0 : aSOpt.searchFlag |= SearchFlags::LEV_RELAXED;
172 : 0 : break;
173 : :
174 : : // case SearchParam::SRCH_NORMAL:
175 : : default:
176 : 0 : aSOpt.algorithmType = SearchAlgorithms_ABSOLUTE;
177 [ # # ]: 0 : if( rParam.IsSrchWordOnly() )
178 : 0 : aSOpt.searchFlag |= SearchFlags::NORM_WORD_ONLY;
179 : 0 : break;
180 : : }
181 [ # # ]: 0 : aSOpt.searchString = rParam.GetSrchStr();
182 [ # # ]: 0 : aSOpt.replaceString = rParam.GetReplaceStr();
183 : 0 : aSOpt.Locale = rLocale;
184 : 0 : aSOpt.transliterateFlags = rParam.GetTransliterationFlags();
185 [ # # ]: 0 : if( !rParam.IsCaseSensitive() )
186 : : {
187 : 0 : aSOpt.searchFlag |= SearchFlags::ALL_IGNORE_CASE;
188 : 0 : aSOpt.transliterateFlags |= ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE;
189 : : }
190 : :
191 [ # # ][ # # ]: 0 : xTextSearch = getXTextSearch( aSOpt );
192 : 0 : }
193 : :
194 : 0 : void TextSearch::SetLocale( const ::com::sun::star::util::SearchOptions& rOptions,
195 : : const ::com::sun::star::lang::Locale& rLocale )
196 : : {
197 : : // convert SearchParam to the UNO SearchOptions
198 : 0 : SearchOptions aSOpt( rOptions );
199 : 0 : aSOpt.Locale = rLocale;
200 : :
201 [ # # ][ # # ]: 0 : xTextSearch = getXTextSearch( aSOpt );
202 : 0 : }
203 : :
204 : :
205 : 82 : TextSearch::~TextSearch()
206 : : {
207 : 82 : }
208 : :
209 : : /*
210 : : * General search methods. These methods will call the respective
211 : : * methods, such as ordinary string searching or regular expression
212 : : * matching, using the method pointer.
213 : : */
214 : : #if defined _MSC_VER
215 : : #pragma optimize("", off)
216 : : #pragma warning(push)
217 : : #pragma warning(disable: 4748)
218 : : #endif
219 : 648 : int TextSearch::SearchFrwrd( const String & rStr, xub_StrLen* pStart,
220 : : xub_StrLen* pEnde, SearchResult* pRes )
221 : : {
222 : 648 : int nRet = 0;
223 : : try
224 : : {
225 [ + - ]: 648 : if( xTextSearch.is() )
226 : : {
227 [ + - ]: 648 : SearchResult aRet( xTextSearch->searchForward(
228 [ + - ][ + - ]: 648 : rStr, *pStart, *pEnde ));
229 [ + + ]: 648 : if( aRet.subRegExpressions > 0 )
230 : : {
231 : 241 : nRet = 1;
232 : : // the XTextsearch returns in startOffset the higher position
233 : : // and the endposition is allways exclusive.
234 : : // The caller of this function will have in startPos the
235 : : // lower pos. and end
236 [ + - ]: 241 : *pStart = (xub_StrLen)aRet.startOffset[ 0 ];
237 [ + - ]: 241 : *pEnde = (xub_StrLen)aRet.endOffset[ 0 ];
238 [ + + ]: 241 : if( pRes )
239 [ + - ]: 73 : *pRes = aRet;
240 [ + - ][ # # ]: 648 : }
241 : : }
242 : : }
243 : 0 : catch ( Exception& )
244 : : {
245 : : SAL_WARN( "unotools.i18n", "SearchForward: Exception caught!" );
246 : : }
247 : 648 : return nRet;
248 : : }
249 : :
250 : 0 : sal_Bool TextSearch::SearchForward( const ::rtl::OUString &rStr,
251 : : sal_Int32* pStart, sal_Int32* pEnd,
252 : : ::com::sun::star::util::SearchResult* pRes)
253 : : {
254 : 0 : sal_Bool nRet = sal_False;
255 : : try
256 : : {
257 [ # # ]: 0 : if( xTextSearch.is() )
258 : : {
259 [ # # ]: 0 : SearchResult aRet( xTextSearch->searchForward(
260 [ # # ]: 0 : rStr, *pStart, *pEnd ));
261 [ # # ]: 0 : if( aRet.subRegExpressions > 0 )
262 : : {
263 : 0 : nRet = sal_True;
264 : : // the XTextsearch returns in startOffset the higher position
265 : : // and the endposition is allways exclusive.
266 : : // The caller of this function will have in startPos the
267 : : // lower pos. and end
268 [ # # ]: 0 : *pStart = aRet.startOffset[ 0 ];
269 [ # # ]: 0 : *pEnd = aRet.endOffset[ 0 ];
270 [ # # ]: 0 : if( pRes )
271 [ # # ]: 0 : *pRes = aRet;
272 [ # # ][ # # ]: 0 : }
273 : : }
274 : : }
275 : 0 : catch ( Exception& )
276 : : {
277 : : SAL_WARN( "unotools.i18n", "SearchForward: Exception caught!" );
278 : : }
279 : 0 : return nRet;
280 : : }
281 : :
282 : :
283 : 0 : int TextSearch::SearchBkwrd( const String & rStr, xub_StrLen* pStart,
284 : : xub_StrLen* pEnde, SearchResult* pRes )
285 : : {
286 : 0 : int nRet = 0;
287 : : try
288 : : {
289 [ # # ]: 0 : if( xTextSearch.is() )
290 : : {
291 [ # # ]: 0 : SearchResult aRet( xTextSearch->searchBackward(
292 [ # # ][ # # ]: 0 : rStr, *pStart, *pEnde ));
293 [ # # ]: 0 : if( aRet.subRegExpressions )
294 : : {
295 : 0 : nRet = 1;
296 : : // the XTextsearch returns in startOffset the higher position
297 : : // and the endposition is allways exclusive.
298 : : // The caller of this function will have in startPos the
299 : : // lower pos. and end
300 [ # # ]: 0 : *pEnde = (xub_StrLen)aRet.startOffset[ 0 ];
301 [ # # ]: 0 : *pStart = (xub_StrLen)aRet.endOffset[ 0 ];
302 [ # # ]: 0 : if( pRes )
303 [ # # ]: 0 : *pRes = aRet;
304 [ # # ][ # # ]: 0 : }
305 : : }
306 : : }
307 : 0 : catch ( Exception& )
308 : : {
309 : : SAL_WARN( "unotools.i18n", "SearchBackward: Exception caught!" );
310 : : }
311 : 0 : return nRet;
312 : : }
313 : :
314 : 0 : void TextSearch::ReplaceBackReferences( String& rReplaceStr, const String &rStr, const SearchResult& rResult )
315 : : {
316 [ # # ]: 0 : if( rResult.subRegExpressions > 0 )
317 : : {
318 : 0 : rtl::OUString sTab( '\t' );
319 : 0 : sal_Unicode sSrchChrs[] = {'\\', '&', '$', 0};
320 [ # # ]: 0 : String sTmp;
321 : 0 : xub_StrLen nPos = 0;
322 : : sal_Unicode sFndChar;
323 [ # # ][ # # ]: 0 : while( STRING_NOTFOUND != ( nPos = rReplaceStr.SearchChar( sSrchChrs, nPos )) )
324 : : {
325 [ # # ]: 0 : if( rReplaceStr.GetChar( nPos ) == '&')
326 : : {
327 : 0 : sal_uInt16 nStart = (sal_uInt16)(rResult.startOffset[0]);
328 : 0 : sal_uInt16 nLength = (sal_uInt16)(rResult.endOffset[0] - rResult.startOffset[0]);
329 [ # # ]: 0 : rReplaceStr.Erase( nPos, 1 ); // delete ampersand
330 : : // replace by found string
331 [ # # ]: 0 : rReplaceStr.Insert( rStr, nStart, nLength, nPos );
332 : : // jump over
333 : 0 : nPos = nPos + nLength;
334 : : }
335 [ # # ]: 0 : else if( rReplaceStr.GetChar( nPos ) == '$')
336 : : {
337 [ # # ]: 0 : if( nPos + 1 < rReplaceStr.Len())
338 : : {
339 : 0 : sFndChar = rReplaceStr.GetChar( nPos + 1 );
340 [ # # ]: 0 : switch(sFndChar)
341 : : { // placeholder for a backward reference?
342 : : case '0':
343 : : case '1':
344 : : case '2':
345 : : case '3':
346 : : case '4':
347 : : case '5':
348 : : case '6':
349 : : case '7':
350 : : case '8':
351 : : case '9':
352 : : {
353 [ # # ]: 0 : rReplaceStr.Erase( nPos, 2 ); // delete both
354 : 0 : int i = sFndChar - '0'; // index
355 [ # # ]: 0 : if(i < rResult.subRegExpressions)
356 : : {
357 : 0 : sal_uInt16 nSttReg = (sal_uInt16)(rResult.startOffset[i]);
358 : 0 : sal_uInt16 nRegLen = (sal_uInt16)(rResult.endOffset[i]);
359 [ # # ]: 0 : if( nRegLen > nSttReg )
360 : 0 : nRegLen = nRegLen - nSttReg;
361 : : else
362 : : {
363 : 0 : nRegLen = nSttReg - nRegLen;
364 : 0 : nSttReg = (sal_uInt16)(rResult.endOffset[i]);
365 : : }
366 : : // Copy reference from found string
367 [ # # ][ # # ]: 0 : sTmp = rStr.Copy((sal_uInt16)nSttReg, (sal_uInt16)nRegLen);
[ # # ]
368 : : // insert
369 [ # # ]: 0 : rReplaceStr.Insert( sTmp, nPos );
370 : : // and step over
371 : 0 : nPos = nPos + sTmp.Len();
372 : : }
373 : : }
374 : 0 : break;
375 : : default:
376 : 0 : nPos += 2; // leave both chars unchanged
377 : 0 : break;
378 : : }
379 : : }
380 : : else
381 : 0 : ++nPos;
382 : : }
383 : : else
384 : : {
385 : : // at least another character?
386 [ # # ]: 0 : if( nPos + 1 < rReplaceStr.Len())
387 : : {
388 : 0 : sFndChar = rReplaceStr.GetChar( nPos + 1 );
389 [ # # # ]: 0 : switch(sFndChar)
390 : : {
391 : : case '\\':
392 : : case '&':
393 : : case '$':
394 [ # # ]: 0 : rReplaceStr.Erase( nPos, 1 );
395 : 0 : nPos++;
396 : 0 : break;
397 : : case 't':
398 [ # # ]: 0 : rReplaceStr.Erase( nPos, 2 ); // delete both
399 [ # # ][ # # ]: 0 : rReplaceStr.Insert( sTab, nPos ); // insert tabulator
[ # # ]
400 : 0 : nPos++; // step over
401 : 0 : break;
402 : : default:
403 : 0 : nPos += 2; // ignore both characters
404 : 0 : break;
405 : : }
406 : : }
407 : : else
408 : 0 : ++nPos;
409 : : }
410 [ # # ]: 0 : }
411 : : }
412 : 0 : }
413 : :
414 : :
415 : : #if defined _MSC_VER
416 : : #pragma optimize("", on)
417 : : #pragma warning(pop)
418 : : #endif
419 : :
420 : : // ............................................................................
421 : : } // namespace utl
422 : : // ............................................................................
423 : :
424 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|