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 "textsearch.hxx"
21 : #include "levdis.hxx"
22 : #include <com/sun/star/lang/Locale.hpp>
23 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
24 : #include <comphelper/processfactory.hxx>
25 : #include <com/sun/star/i18n/BreakIterator.hpp>
26 : #include <com/sun/star/i18n/UnicodeType.hpp>
27 : #include <com/sun/star/util/SearchFlags.hpp>
28 : #include <com/sun/star/i18n/WordType.hpp>
29 : #include <com/sun/star/i18n/ScriptType.hpp>
30 : #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
31 : #include <com/sun/star/i18n/CharacterClassification.hpp>
32 : #include <com/sun/star/i18n/KCharacterType.hpp>
33 : #include <com/sun/star/i18n/Transliteration.hpp>
34 : #include <com/sun/star/registry/XRegistryKey.hpp>
35 : #include <cppuhelper/factory.hxx>
36 : #include <cppuhelper/supportsservice.hxx>
37 : #include <cppuhelper/weak.hxx>
38 :
39 : #ifdef _MSC_VER
40 : // get rid of that dumb compiler warning
41 : // identifier was truncated to '255' characters in the debug information
42 : // for STL template usage, if .pdb files are to be created
43 : #pragma warning( disable: 4786 )
44 : #endif
45 :
46 : #include <string.h>
47 :
48 : using namespace ::com::sun::star::util;
49 : using namespace ::com::sun::star::uno;
50 : using namespace ::com::sun::star::lang;
51 : using namespace ::com::sun::star::i18n;
52 : using namespace ::com::sun::star;
53 :
54 : static const sal_Int32 COMPLEX_TRANS_MASK_TMP =
55 : TransliterationModules_ignoreBaFa_ja_JP |
56 : TransliterationModules_ignoreIterationMark_ja_JP |
57 : TransliterationModules_ignoreTiJi_ja_JP |
58 : TransliterationModules_ignoreHyuByu_ja_JP |
59 : TransliterationModules_ignoreSeZe_ja_JP |
60 : TransliterationModules_ignoreIandEfollowedByYa_ja_JP |
61 : TransliterationModules_ignoreKiKuFollowedBySa_ja_JP |
62 : TransliterationModules_ignoreProlongedSoundMark_ja_JP;
63 :
64 : // These 2 transliterations are simple but need to take effect in
65 : // complex transliteration.
66 : static const sal_Int32 COMPLEX_TRANS_MASK =
67 : COMPLEX_TRANS_MASK_TMP |
68 : TransliterationModules_IGNORE_KANA |
69 : TransliterationModules_FULLWIDTH_HALFWIDTH;
70 :
71 : static const sal_Int32 SIMPLE_TRANS_MASK = ~COMPLEX_TRANS_MASK;
72 :
73 : // Regex patterns are case sensitive.
74 : static const sal_Int32 SIMPLE_TRANS_MASK_REPATTERN =
75 : ~(COMPLEX_TRANS_MASK |
76 : TransliterationModules_IGNORE_CASE |
77 : TransliterationModules_UPPERCASE_LOWERCASE |
78 : TransliterationModules_LOWERCASE_UPPERCASE);
79 :
80 :
81 112 : TextSearch::TextSearch(const Reference < XComponentContext > & rxContext)
82 : : m_xContext( rxContext )
83 : , pJumpTable( 0 )
84 : , pJumpTable2( 0 )
85 : , pRegexMatcher( NULL )
86 112 : , pWLD( 0 )
87 : {
88 112 : SearchOptions aOpt;
89 112 : aOpt.algorithmType = SearchAlgorithms_ABSOLUTE;
90 112 : aOpt.searchFlag = SearchFlags::ALL_IGNORE_CASE;
91 : //aOpt.Locale = ???;
92 112 : setOptions( aOpt );
93 112 : }
94 :
95 288 : TextSearch::~TextSearch()
96 : {
97 96 : delete pRegexMatcher;
98 96 : delete pWLD;
99 96 : delete pJumpTable;
100 96 : delete pJumpTable2;
101 192 : }
102 :
103 220 : void TextSearch::setOptions( const SearchOptions& rOptions ) throw( RuntimeException, std::exception )
104 : {
105 220 : aSrchPara = rOptions;
106 :
107 220 : delete pRegexMatcher, pRegexMatcher = NULL;
108 220 : delete pWLD, pWLD = 0;
109 220 : delete pJumpTable, pJumpTable = 0;
110 220 : delete pJumpTable2, pJumpTable2 = 0;
111 :
112 : // Create Transliteration class
113 220 : if( aSrchPara.transliterateFlags & SIMPLE_TRANS_MASK )
114 : {
115 88 : if( !xTranslit.is() )
116 88 : xTranslit.set( Transliteration::create( m_xContext ) );
117 88 : xTranslit->loadModule(
118 88 : (TransliterationModules)( aSrchPara.transliterateFlags & SIMPLE_TRANS_MASK ),
119 176 : aSrchPara.Locale);
120 : }
121 132 : else if( xTranslit.is() )
122 0 : xTranslit = 0;
123 :
124 : // Create Transliteration for 2<->1, 2<->2 transliteration
125 220 : if ( aSrchPara.transliterateFlags & COMPLEX_TRANS_MASK )
126 : {
127 0 : if( !xTranslit2.is() )
128 0 : xTranslit2.set( Transliteration::create( m_xContext ) );
129 : // Load transliteration module
130 0 : xTranslit2->loadModule(
131 0 : (TransliterationModules)( aSrchPara.transliterateFlags & COMPLEX_TRANS_MASK ),
132 0 : aSrchPara.Locale);
133 : }
134 :
135 220 : if ( !xBreak.is() )
136 112 : xBreak = com::sun::star::i18n::BreakIterator::create( m_xContext );
137 :
138 220 : sSrchStr = aSrchPara.searchString;
139 :
140 : // Transliterate search string.
141 220 : if (aSrchPara.algorithmType == SearchAlgorithms_REGEXP)
142 : {
143 34 : if (aSrchPara.transliterateFlags & SIMPLE_TRANS_MASK_REPATTERN)
144 : {
145 0 : if ((aSrchPara.transliterateFlags & SIMPLE_TRANS_MASK_REPATTERN) !=
146 : (aSrchPara.transliterateFlags & SIMPLE_TRANS_MASK))
147 : {
148 : com::sun::star::uno::Reference< XExtendedTransliteration > xTranslitPattern(
149 0 : Transliteration::create( m_xContext ));
150 0 : if (xTranslitPattern.is())
151 : {
152 0 : xTranslitPattern->loadModule(
153 0 : (TransliterationModules)( aSrchPara.transliterateFlags & SIMPLE_TRANS_MASK_REPATTERN ),
154 0 : aSrchPara.Locale);
155 0 : sSrchStr = xTranslitPattern->transliterateString2String(
156 0 : aSrchPara.searchString, 0, aSrchPara.searchString.getLength());
157 0 : }
158 : }
159 : else
160 : {
161 0 : if (xTranslit.is())
162 0 : sSrchStr = xTranslit->transliterateString2String(
163 0 : aSrchPara.searchString, 0, aSrchPara.searchString.getLength());
164 : }
165 : // xTranslit2 complex transliterated sSrchStr2 is not used in
166 : // regex, see TextSearch::searchForward() and
167 : // TextSearch::searchBackward()
168 : }
169 : }
170 : else
171 : {
172 186 : if ( xTranslit.is() && aSrchPara.transliterateFlags & SIMPLE_TRANS_MASK )
173 222 : sSrchStr = xTranslit->transliterateString2String(
174 148 : aSrchPara.searchString, 0, aSrchPara.searchString.getLength());
175 :
176 186 : if ( xTranslit2.is() && aSrchPara.transliterateFlags & COMPLEX_TRANS_MASK )
177 0 : sSrchStr2 = xTranslit2->transliterateString2String(
178 0 : aSrchPara.searchString, 0, aSrchPara.searchString.getLength());
179 : }
180 :
181 : // When start or end of search string is a complex script type, we need to
182 : // make sure the result boundary is not located in the middle of cell.
183 220 : checkCTLStart = (xBreak.is() && (xBreak->getScriptType(sSrchStr, 0) ==
184 220 : ScriptType::COMPLEX));
185 440 : checkCTLEnd = (xBreak.is() && (xBreak->getScriptType(sSrchStr,
186 440 : sSrchStr.getLength()-1) == ScriptType::COMPLEX));
187 :
188 220 : switch( aSrchPara.algorithmType)
189 : {
190 : case SearchAlgorithms_REGEXP:
191 34 : fnForward = &TextSearch::RESrchFrwrd;
192 34 : fnBackward = &TextSearch::RESrchBkwrd;
193 34 : RESrchPrepare( aSrchPara);
194 34 : break;
195 :
196 : case SearchAlgorithms_APPROXIMATE:
197 0 : fnForward = &TextSearch::ApproxSrchFrwrd;
198 0 : fnBackward = &TextSearch::ApproxSrchBkwrd;
199 :
200 0 : pWLD = new WLevDistance( sSrchStr.getStr(), aSrchPara.changedChars,
201 : aSrchPara.insertedChars, aSrchPara.deletedChars,
202 0 : 0 != (SearchFlags::LEV_RELAXED & aSrchPara.searchFlag ) );
203 :
204 0 : nLimit = pWLD->GetLimit();
205 0 : break;
206 :
207 : default:
208 186 : fnForward = &TextSearch::NSrchFrwrd;
209 186 : fnBackward = &TextSearch::NSrchBkwrd;
210 186 : break;
211 : }
212 220 : }
213 :
214 158 : sal_Int32 FindPosInSeq_Impl( const Sequence <sal_Int32>& rOff, sal_Int32 nPos )
215 : {
216 158 : sal_Int32 nRet = 0, nEnd = rOff.getLength();
217 158 : while( nRet < nEnd && nPos > rOff[ nRet ] ) ++nRet;
218 158 : return nRet;
219 : }
220 :
221 0 : bool TextSearch::isCellStart(const OUString& searchStr, sal_Int32 nPos)
222 : throw( RuntimeException )
223 : {
224 : sal_Int32 nDone;
225 0 : return nPos == xBreak->previousCharacters(searchStr, nPos+1,
226 0 : aSrchPara.Locale, CharacterIteratorMode::SKIPCELL, 1, nDone);
227 : }
228 :
229 2374 : SearchResult TextSearch::searchForward( const OUString& searchStr, sal_Int32 startPos, sal_Int32 endPos )
230 : throw( RuntimeException, std::exception )
231 : {
232 2374 : SearchResult sres;
233 :
234 4748 : OUString in_str(searchStr);
235 2374 : sal_Int32 newStartPos = startPos;
236 2374 : sal_Int32 newEndPos = endPos;
237 :
238 2374 : bUsePrimarySrchStr = true;
239 :
240 2374 : if ( xTranslit.is() )
241 : {
242 : // apply normal transliteration (1<->1, 1<->0)
243 872 : com::sun::star::uno::Sequence <sal_Int32> offset( in_str.getLength());
244 872 : in_str = xTranslit->transliterate( searchStr, 0, in_str.getLength(), offset );
245 :
246 : // JP 20.6.2001: also the start and end positions must be corrected!
247 872 : if( startPos )
248 158 : newStartPos = FindPosInSeq_Impl( offset, startPos );
249 :
250 872 : if( endPos < searchStr.getLength() )
251 0 : newEndPos = FindPosInSeq_Impl( offset, endPos );
252 : else
253 872 : newEndPos = in_str.getLength();
254 :
255 872 : sres = (this->*fnForward)( in_str, newStartPos, newEndPos );
256 :
257 : // Map offsets back to untransliterated string.
258 872 : const sal_Int32 nOffsets = offset.getLength();
259 872 : if (nOffsets)
260 : {
261 : // For regex nGroups is the number of groups+1 with group 0 being
262 : // the entire match.
263 872 : const sal_Int32 nGroups = sres.startOffset.getLength();
264 1168 : for ( sal_Int32 k = 0; k < nGroups; k++ )
265 : {
266 296 : const sal_Int32 nStart = sres.startOffset[k];
267 296 : if (nStart > 0)
268 160 : sres.startOffset[k] = (nStart < nOffsets ? offset[nStart] : (offset[nOffsets - 1] + 1));
269 : // JP 20.6.2001: end is ever exclusive and then don't return
270 : // the position of the next character - return the
271 : // next position behind the last found character!
272 : // "a b c" find "b" must return 2,3 and not 2,4!!!
273 296 : const sal_Int32 nStop = sres.endOffset[k];
274 296 : if (nStop > 0)
275 296 : sres.endOffset[k] = offset[(nStop <= nOffsets ? nStop : nOffsets) - 1] + 1;
276 : }
277 872 : }
278 : }
279 : else
280 : {
281 1502 : sres = (this->*fnForward)( in_str, startPos, endPos );
282 : }
283 :
284 2374 : if ( xTranslit2.is() && aSrchPara.algorithmType != SearchAlgorithms_REGEXP)
285 : {
286 0 : SearchResult sres2;
287 :
288 0 : in_str = OUString(searchStr);
289 0 : com::sun::star::uno::Sequence <sal_Int32> offset( in_str.getLength());
290 :
291 0 : in_str = xTranslit2->transliterate( searchStr, 0, in_str.getLength(), offset );
292 :
293 0 : if( startPos )
294 0 : startPos = FindPosInSeq_Impl( offset, startPos );
295 :
296 0 : if( endPos < searchStr.getLength() )
297 0 : endPos = FindPosInSeq_Impl( offset, endPos );
298 : else
299 0 : endPos = in_str.getLength();
300 :
301 0 : bUsePrimarySrchStr = false;
302 0 : sres2 = (this->*fnForward)( in_str, startPos, endPos );
303 :
304 0 : for ( int k = 0; k < sres2.startOffset.getLength(); k++ )
305 : {
306 0 : if (sres2.startOffset[k])
307 0 : sres2.startOffset[k] = offset[sres2.startOffset[k]-1] + 1;
308 0 : if (sres2.endOffset[k])
309 0 : sres2.endOffset[k] = offset[sres2.endOffset[k]-1] + 1;
310 : }
311 :
312 : // pick first and long one
313 0 : if ( sres.subRegExpressions == 0)
314 0 : return sres2;
315 0 : if ( sres2.subRegExpressions == 1)
316 : {
317 0 : if ( sres.startOffset[0] > sres2.startOffset[0])
318 0 : return sres2;
319 0 : else if ( sres.startOffset[0] == sres2.startOffset[0] &&
320 0 : sres.endOffset[0] < sres2.endOffset[0])
321 0 : return sres2;
322 0 : }
323 : }
324 :
325 4748 : return sres;
326 : }
327 :
328 2 : SearchResult TextSearch::searchBackward( const OUString& searchStr, sal_Int32 startPos, sal_Int32 endPos )
329 : throw(RuntimeException, std::exception)
330 : {
331 2 : SearchResult sres;
332 :
333 4 : OUString in_str(searchStr);
334 2 : sal_Int32 newStartPos = startPos;
335 2 : sal_Int32 newEndPos = endPos;
336 :
337 2 : bUsePrimarySrchStr = true;
338 :
339 2 : if ( xTranslit.is() )
340 : {
341 : // apply only simple 1<->1 transliteration here
342 0 : com::sun::star::uno::Sequence <sal_Int32> offset( in_str.getLength());
343 0 : in_str = xTranslit->transliterate( searchStr, 0, in_str.getLength(), offset );
344 :
345 : // JP 20.6.2001: also the start and end positions must be corrected!
346 0 : if( startPos < searchStr.getLength() )
347 0 : newStartPos = FindPosInSeq_Impl( offset, startPos );
348 : else
349 0 : newStartPos = in_str.getLength();
350 :
351 0 : if( endPos )
352 0 : newEndPos = FindPosInSeq_Impl( offset, endPos );
353 :
354 0 : sres = (this->*fnBackward)( in_str, newStartPos, newEndPos );
355 :
356 : // Map offsets back to untransliterated string.
357 0 : const sal_Int32 nOffsets = offset.getLength();
358 0 : if (nOffsets)
359 : {
360 : // For regex nGroups is the number of groups+1 with group 0 being
361 : // the entire match.
362 0 : const sal_Int32 nGroups = sres.startOffset.getLength();
363 0 : for ( sal_Int32 k = 0; k < nGroups; k++ )
364 : {
365 0 : const sal_Int32 nStart = sres.startOffset[k];
366 0 : if (nStart > 0)
367 0 : sres.startOffset[k] = offset[(nStart <= nOffsets ? nStart : nOffsets) - 1] + 1;
368 : // JP 20.6.2001: end is ever exclusive and then don't return
369 : // the position of the next character - return the
370 : // next position behind the last found character!
371 : // "a b c" find "b" must return 2,3 and not 2,4!!!
372 0 : const sal_Int32 nStop = sres.endOffset[k];
373 0 : if (nStop > 0)
374 0 : sres.endOffset[k] = (nStop < nOffsets ? offset[nStop] : (offset[nOffsets - 1] + 1));
375 : }
376 0 : }
377 : }
378 : else
379 : {
380 2 : sres = (this->*fnBackward)( in_str, startPos, endPos );
381 : }
382 :
383 2 : if ( xTranslit2.is() && aSrchPara.algorithmType != SearchAlgorithms_REGEXP )
384 : {
385 0 : SearchResult sres2;
386 :
387 0 : in_str = OUString(searchStr);
388 0 : com::sun::star::uno::Sequence <sal_Int32> offset( in_str.getLength());
389 :
390 0 : in_str = xTranslit2->transliterate(searchStr, 0, in_str.getLength(), offset);
391 :
392 0 : if( startPos < searchStr.getLength() )
393 0 : startPos = FindPosInSeq_Impl( offset, startPos );
394 : else
395 0 : startPos = in_str.getLength();
396 :
397 0 : if( endPos )
398 0 : endPos = FindPosInSeq_Impl( offset, endPos );
399 :
400 0 : bUsePrimarySrchStr = false;
401 0 : sres2 = (this->*fnBackward)( in_str, startPos, endPos );
402 :
403 0 : for( int k = 0; k < sres2.startOffset.getLength(); k++ )
404 : {
405 0 : if (sres2.startOffset[k])
406 0 : sres2.startOffset[k] = offset[sres2.startOffset[k]-1]+1;
407 0 : if (sres2.endOffset[k])
408 0 : sres2.endOffset[k] = offset[sres2.endOffset[k]-1]+1;
409 : }
410 :
411 : // pick last and long one
412 0 : if ( sres.subRegExpressions == 0 )
413 0 : return sres2;
414 0 : if ( sres2.subRegExpressions == 1 )
415 : {
416 0 : if ( sres.startOffset[0] < sres2.startOffset[0] )
417 0 : return sres2;
418 0 : if ( sres.startOffset[0] == sres2.startOffset[0] &&
419 0 : sres.endOffset[0] > sres2.endOffset[0] )
420 0 : return sres2;
421 0 : }
422 : }
423 :
424 4 : return sres;
425 : }
426 :
427 :
428 :
429 0 : bool TextSearch::IsDelimiter( const OUString& rStr, sal_Int32 nPos ) const
430 : {
431 0 : bool bRet = true;
432 0 : if( '\x7f' != rStr[nPos])
433 : {
434 0 : if ( !xCharClass.is() )
435 0 : xCharClass = CharacterClassification::create( m_xContext );
436 0 : sal_Int32 nCType = xCharClass->getCharacterType( rStr, nPos,
437 0 : aSrchPara.Locale );
438 0 : if( 0 != (( KCharacterType::DIGIT | KCharacterType::ALPHA |
439 0 : KCharacterType::LETTER ) & nCType ) )
440 0 : bRet = false;
441 : }
442 0 : return bRet;
443 : }
444 :
445 : // --------- helper methods for Boyer-Moore like text searching ----------
446 : // TODO: use ICU's regex UREGEX_LITERAL mode instead when it becomes available
447 :
448 438 : void TextSearch::MakeForwardTab()
449 : {
450 : // create the jumptable for the search text
451 438 : if( pJumpTable )
452 : {
453 368 : if( bIsForwardTab )
454 806 : return ; // the jumpTable is ok
455 0 : delete pJumpTable;
456 : }
457 70 : bIsForwardTab = true;
458 :
459 70 : sal_Int32 n, nLen = sSrchStr.getLength();
460 70 : pJumpTable = new TextSearchJumpTable;
461 :
462 482 : for( n = 0; n < nLen - 1; ++n )
463 : {
464 412 : sal_Unicode cCh = sSrchStr[n];
465 412 : sal_Int32 nDiff = nLen - n - 1;
466 412 : TextSearchJumpTable::value_type aEntry( cCh, nDiff );
467 :
468 : ::std::pair< TextSearchJumpTable::iterator, bool > aPair =
469 412 : pJumpTable->insert( aEntry );
470 412 : if ( !aPair.second )
471 132 : (*(aPair.first)).second = nDiff;
472 : }
473 : }
474 :
475 0 : void TextSearch::MakeForwardTab2()
476 : {
477 : // create the jumptable for the search text
478 0 : if( pJumpTable2 )
479 : {
480 0 : if( bIsForwardTab )
481 0 : return ; // the jumpTable is ok
482 0 : delete pJumpTable2;
483 : }
484 0 : bIsForwardTab = true;
485 :
486 0 : sal_Int32 n, nLen = sSrchStr2.getLength();
487 0 : pJumpTable2 = new TextSearchJumpTable;
488 :
489 0 : for( n = 0; n < nLen - 1; ++n )
490 : {
491 0 : sal_Unicode cCh = sSrchStr2[n];
492 0 : sal_Int32 nDiff = nLen - n - 1;
493 :
494 0 : TextSearchJumpTable::value_type aEntry( cCh, nDiff );
495 : ::std::pair< TextSearchJumpTable::iterator, bool > aPair =
496 0 : pJumpTable2->insert( aEntry );
497 0 : if ( !aPair.second )
498 0 : (*(aPair.first)).second = nDiff;
499 : }
500 : }
501 :
502 0 : void TextSearch::MakeBackwardTab()
503 : {
504 : // create the jumptable for the search text
505 0 : if( pJumpTable )
506 : {
507 0 : if( !bIsForwardTab )
508 0 : return ; // the jumpTable is ok
509 0 : delete pJumpTable;
510 : }
511 0 : bIsForwardTab = false;
512 :
513 0 : sal_Int32 n, nLen = sSrchStr.getLength();
514 0 : pJumpTable = new TextSearchJumpTable;
515 :
516 0 : for( n = nLen-1; n > 0; --n )
517 : {
518 0 : sal_Unicode cCh = sSrchStr[n];
519 0 : TextSearchJumpTable::value_type aEntry( cCh, n );
520 : ::std::pair< TextSearchJumpTable::iterator, bool > aPair =
521 0 : pJumpTable->insert( aEntry );
522 0 : if ( !aPair.second )
523 0 : (*(aPair.first)).second = n;
524 : }
525 : }
526 :
527 0 : void TextSearch::MakeBackwardTab2()
528 : {
529 : // create the jumptable for the search text
530 0 : if( pJumpTable2 )
531 : {
532 0 : if( !bIsForwardTab )
533 0 : return ; // the jumpTable is ok
534 0 : delete pJumpTable2;
535 : }
536 0 : bIsForwardTab = false;
537 :
538 0 : sal_Int32 n, nLen = sSrchStr2.getLength();
539 0 : pJumpTable2 = new TextSearchJumpTable;
540 :
541 0 : for( n = nLen-1; n > 0; --n )
542 : {
543 0 : sal_Unicode cCh = sSrchStr2[n];
544 0 : TextSearchJumpTable::value_type aEntry( cCh, n );
545 : ::std::pair< TextSearchJumpTable::iterator, bool > aPair =
546 0 : pJumpTable2->insert( aEntry );
547 0 : if ( !aPair.second )
548 0 : (*(aPair.first)).second = n;
549 : }
550 : }
551 :
552 1824 : sal_Int32 TextSearch::GetDiff( const sal_Unicode cChr ) const
553 : {
554 : TextSearchJumpTable *pJump;
555 1824 : OUString sSearchKey;
556 :
557 1824 : if ( bUsePrimarySrchStr ) {
558 1824 : pJump = pJumpTable;
559 1824 : sSearchKey = sSrchStr;
560 : } else {
561 0 : pJump = pJumpTable2;
562 0 : sSearchKey = sSrchStr2;
563 : }
564 :
565 1824 : TextSearchJumpTable::const_iterator iLook = pJump->find( cChr );
566 1824 : if ( iLook == pJump->end() )
567 1530 : return sSearchKey.getLength();
568 294 : return (*iLook).second;
569 : }
570 :
571 :
572 796 : SearchResult TextSearch::NSrchFrwrd( const OUString& searchStr, sal_Int32 startPos, sal_Int32 endPos )
573 : throw(RuntimeException)
574 : {
575 796 : SearchResult aRet;
576 796 : aRet.subRegExpressions = 0;
577 :
578 1592 : OUString sSearchKey = bUsePrimarySrchStr ? sSrchStr : sSrchStr2;
579 :
580 1592 : OUString aStr( searchStr );
581 796 : sal_Int32 nSuchIdx = aStr.getLength();
582 796 : sal_Int32 nEnde = endPos;
583 796 : if( !nSuchIdx || !sSearchKey.getLength() || sSearchKey.getLength() > nSuchIdx )
584 358 : return aRet;
585 :
586 :
587 438 : if( nEnde < sSearchKey.getLength() ) // position inside the search region ?
588 0 : return aRet;
589 :
590 438 : nEnde -= sSearchKey.getLength();
591 :
592 438 : if (bUsePrimarySrchStr)
593 438 : MakeForwardTab(); // create the jumptable
594 : else
595 0 : MakeForwardTab2();
596 :
597 2262 : for (sal_Int32 nCmpIdx = startPos; // start position for the search
598 : nCmpIdx <= nEnde;
599 1824 : nCmpIdx += GetDiff( aStr[nCmpIdx + sSearchKey.getLength()-1]))
600 : {
601 : // if the match would be the completed cells, skip it.
602 2082 : if ( (checkCTLStart && !isCellStart( aStr, nCmpIdx )) || (checkCTLEnd
603 0 : && !isCellStart( aStr, nCmpIdx + sSearchKey.getLength())) )
604 0 : continue;
605 :
606 2082 : nSuchIdx = sSearchKey.getLength() - 1;
607 6396 : while( nSuchIdx >= 0 && sSearchKey[nSuchIdx] == aStr[nCmpIdx + nSuchIdx])
608 : {
609 2490 : if( nSuchIdx == 0 )
610 : {
611 258 : if( SearchFlags::NORM_WORD_ONLY & aSrchPara.searchFlag )
612 : {
613 0 : sal_Int32 nFndEnd = nCmpIdx + sSearchKey.getLength();
614 0 : bool bAtStart = !nCmpIdx;
615 0 : bool bAtEnd = nFndEnd == endPos;
616 0 : bool bDelimBefore = bAtStart || IsDelimiter( aStr, nCmpIdx-1 );
617 0 : bool bDelimBehind = bAtEnd || IsDelimiter( aStr, nFndEnd );
618 : // * 1 -> only one word in the paragraph
619 : // * 2 -> at begin of paragraph
620 : // * 3 -> at end of paragraph
621 : // * 4 -> inside the paragraph
622 0 : if( !( ( bAtStart && bAtEnd ) || // 1
623 0 : ( bAtStart && bDelimBehind ) || // 2
624 0 : ( bAtEnd && bDelimBefore ) || // 3
625 0 : ( bDelimBefore && bDelimBehind ))) // 4
626 : break;
627 : }
628 :
629 258 : aRet.subRegExpressions = 1;
630 258 : aRet.startOffset.realloc( 1 );
631 258 : aRet.startOffset[ 0 ] = nCmpIdx;
632 258 : aRet.endOffset.realloc( 1 );
633 258 : aRet.endOffset[ 0 ] = nCmpIdx + sSearchKey.getLength();
634 :
635 258 : return aRet;
636 : }
637 : else
638 2232 : nSuchIdx--;
639 : }
640 : }
641 180 : return aRet;
642 : }
643 :
644 0 : SearchResult TextSearch::NSrchBkwrd( const OUString& searchStr, sal_Int32 startPos, sal_Int32 endPos )
645 : throw(RuntimeException)
646 : {
647 0 : SearchResult aRet;
648 0 : aRet.subRegExpressions = 0;
649 :
650 0 : OUString sSearchKey = bUsePrimarySrchStr ? sSrchStr : sSrchStr2;
651 :
652 0 : OUString aStr( searchStr );
653 0 : sal_Int32 nSuchIdx = aStr.getLength();
654 0 : sal_Int32 nEnde = endPos;
655 0 : if( nSuchIdx == 0 || sSearchKey.isEmpty() || sSearchKey.getLength() > nSuchIdx)
656 0 : return aRet;
657 :
658 0 : if (bUsePrimarySrchStr)
659 0 : MakeBackwardTab(); // create the jumptable
660 : else
661 0 : MakeBackwardTab2();
662 :
663 0 : if( nEnde == nSuchIdx ) // end position for the search
664 0 : nEnde = sSearchKey.getLength();
665 : else
666 0 : nEnde += sSearchKey.getLength();
667 :
668 0 : sal_Int32 nCmpIdx = startPos; // start position for the search
669 :
670 0 : while (nCmpIdx >= nEnde)
671 : {
672 : // if the match would be the completed cells, skip it.
673 0 : if ( (!checkCTLStart || isCellStart( aStr, nCmpIdx -
674 0 : sSearchKey.getLength() )) && (!checkCTLEnd ||
675 0 : isCellStart( aStr, nCmpIdx)))
676 : {
677 0 : nSuchIdx = 0;
678 0 : while( nSuchIdx < sSearchKey.getLength() && sSearchKey[nSuchIdx] ==
679 0 : aStr[nCmpIdx + nSuchIdx - sSearchKey.getLength()] )
680 0 : nSuchIdx++;
681 0 : if( nSuchIdx >= sSearchKey.getLength() )
682 : {
683 0 : if( SearchFlags::NORM_WORD_ONLY & aSrchPara.searchFlag )
684 : {
685 0 : sal_Int32 nFndStt = nCmpIdx - sSearchKey.getLength();
686 0 : bool bAtStart = !nFndStt;
687 0 : bool bAtEnd = nCmpIdx == startPos;
688 0 : bool bDelimBehind = bAtEnd || IsDelimiter( aStr, nCmpIdx );
689 0 : bool bDelimBefore = bAtStart || // begin of paragraph
690 0 : IsDelimiter( aStr, nFndStt-1 );
691 : // * 1 -> only one word in the paragraph
692 : // * 2 -> at begin of paragraph
693 : // * 3 -> at end of paragraph
694 : // * 4 -> inside the paragraph
695 0 : if( ( bAtStart && bAtEnd ) || // 1
696 0 : ( bAtStart && bDelimBehind ) || // 2
697 0 : ( bAtEnd && bDelimBefore ) || // 3
698 0 : ( bDelimBefore && bDelimBehind )) // 4
699 : {
700 0 : aRet.subRegExpressions = 1;
701 0 : aRet.startOffset.realloc( 1 );
702 0 : aRet.startOffset[ 0 ] = nCmpIdx;
703 0 : aRet.endOffset.realloc( 1 );
704 0 : aRet.endOffset[ 0 ] = nCmpIdx - sSearchKey.getLength();
705 0 : return aRet;
706 : }
707 : }
708 : else
709 : {
710 0 : aRet.subRegExpressions = 1;
711 0 : aRet.startOffset.realloc( 1 );
712 0 : aRet.startOffset[ 0 ] = nCmpIdx;
713 0 : aRet.endOffset.realloc( 1 );
714 0 : aRet.endOffset[ 0 ] = nCmpIdx - sSearchKey.getLength();
715 0 : return aRet;
716 : }
717 : }
718 : }
719 0 : nSuchIdx = GetDiff( aStr[nCmpIdx - sSearchKey.getLength()] );
720 0 : if( nCmpIdx < nSuchIdx )
721 0 : return aRet;
722 0 : nCmpIdx -= nSuchIdx;
723 : }
724 0 : return aRet;
725 : }
726 :
727 34 : void TextSearch::RESrchPrepare( const ::com::sun::star::util::SearchOptions& rOptions)
728 : {
729 : // select the transliterated pattern string
730 : const OUString& rPatternStr =
731 34 : (rOptions.transliterateFlags & SIMPLE_TRANS_MASK) ? sSrchStr
732 34 : : ((rOptions.transliterateFlags & COMPLEX_TRANS_MASK) ? sSrchStr2 : rOptions.searchString);
733 :
734 34 : sal_uInt32 nIcuSearchFlags = UREGEX_UWORD; // request UAX#29 unicode capability
735 : // map com::sun::star::util::SearchFlags to ICU uregex.h flags
736 : // TODO: REG_EXTENDED, REG_NOT_BEGINOFLINE, REG_NOT_ENDOFLINE
737 : // REG_NEWLINE is neither properly defined nor used anywhere => not implemented
738 : // REG_NOSUB is not used anywhere => not implemented
739 : // NORM_WORD_ONLY is only used for SearchAlgorithm==Absolute
740 : // LEV_RELAXED is only used for SearchAlgorithm==Approximate
741 : // Note that the search flag ALL_IGNORE_CASE is deprecated in UNO
742 : // probably because the transliteration flag IGNORE_CASE handles it as well.
743 34 : if( (rOptions.searchFlag & com::sun::star::util::SearchFlags::ALL_IGNORE_CASE) != 0
744 22 : || (rOptions.transliterateFlags & TransliterationModules_IGNORE_CASE) != 0)
745 16 : nIcuSearchFlags |= UREGEX_CASE_INSENSITIVE;
746 34 : UErrorCode nIcuErr = U_ZERO_ERROR;
747 : // assumption: transliteration didn't mangle regexp control chars
748 34 : IcuUniString aIcuSearchPatStr( (const UChar*)rPatternStr.getStr(), rPatternStr.getLength());
749 : #ifndef DISABLE_WORDBOUND_EMULATION
750 : // for conveniance specific syntax elements of the old regex engine are emulated
751 : // - by replacing \< with "word-break followed by a look-ahead word-char"
752 34 : static const IcuUniString aChevronPatternB( "\\\\<", -1, IcuUniString::kInvariant);
753 34 : static const IcuUniString aChevronReplaceB( "\\\\b(?=\\\\w)", -1, IcuUniString::kInvariant);
754 34 : static RegexMatcher aChevronMatcherB( aChevronPatternB, 0, nIcuErr);
755 34 : aChevronMatcherB.reset( aIcuSearchPatStr);
756 34 : aIcuSearchPatStr = aChevronMatcherB.replaceAll( aChevronReplaceB, nIcuErr);
757 34 : aChevronMatcherB.reset();
758 : // - by replacing \> with "look-behind word-char followed by a word-break"
759 34 : static const IcuUniString aChevronPatternE( "\\\\>", -1, IcuUniString::kInvariant);
760 34 : static const IcuUniString aChevronReplaceE( "(?<=\\\\w)\\\\b", -1, IcuUniString::kInvariant);
761 34 : static RegexMatcher aChevronMatcherE( aChevronPatternE, 0, nIcuErr);
762 34 : aChevronMatcherE.reset( aIcuSearchPatStr);
763 34 : aIcuSearchPatStr = aChevronMatcherE.replaceAll( aChevronReplaceE, nIcuErr);
764 34 : aChevronMatcherE.reset();
765 : #endif
766 34 : pRegexMatcher = new RegexMatcher( aIcuSearchPatStr, nIcuSearchFlags, nIcuErr);
767 34 : if (nIcuErr)
768 : {
769 : SAL_INFO( "i18npool", "TextSearch::RESrchPrepare UErrorCode " << nIcuErr);
770 0 : delete pRegexMatcher;
771 0 : pRegexMatcher = NULL;
772 : }
773 : else
774 : {
775 : // Pathological patterns may result in exponential run time making the
776 : // application appear to be frozen. Limit that. Documentation for this
777 : // call says
778 : // https://ssl.icu-project.org/apiref/icu4c/classicu_1_1RegexMatcher.html#a6ebcfcab4fe6a38678c0291643a03a00
779 : // "The units of the limit are steps of the match engine.
780 : // Correspondence with actual processor time will depend on the speed
781 : // of the processor and the details of the specific pattern, but will
782 : // typically be on the order of milliseconds."
783 : // Just what is a good value? 42 is always an answer ... the 23 enigma
784 : // as well.. which on the dev's machine is roughly 50 seconds with the
785 : // pattern of fdo#70627.
786 : /* TODO: make this a configuration settable value and possibly take
787 : * complexity of expression into account and maybe even length of text
788 : * to be matched; currently (2013-11-25) that is at most one 64k
789 : * paragraph per RESrchFrwrd()/RESrchBkwrd() call. */
790 34 : pRegexMatcher->setTimeLimit( 23*1000, nIcuErr);
791 34 : }
792 34 : }
793 :
794 :
795 :
796 1584 : static bool lcl_findRegex( RegexMatcher * pRegexMatcher, sal_Int32 nStartPos, UErrorCode & rIcuErr )
797 : {
798 1584 : if (!pRegexMatcher->find( nStartPos, rIcuErr))
799 : {
800 : /* TODO: future versions could pass the UErrorCode or translations
801 : * thereof to the caller, for example to inform the user of
802 : * U_REGEX_TIME_OUT. The strange thing though is that an error is set
803 : * only after the second call that returns immediately and not if
804 : * timeout occurred on the first call?!? */
805 : SAL_INFO( "i18npool", "lcl_findRegex UErrorCode " << rIcuErr);
806 276 : return false;
807 : }
808 1308 : return true;
809 : }
810 :
811 1578 : SearchResult TextSearch::RESrchFrwrd( const OUString& searchStr,
812 : sal_Int32 startPos, sal_Int32 endPos )
813 : throw(RuntimeException)
814 : {
815 1578 : SearchResult aRet;
816 1578 : aRet.subRegExpressions = 0;
817 1578 : if( !pRegexMatcher)
818 0 : return aRet;
819 :
820 1578 : if( endPos > searchStr.getLength())
821 0 : endPos = searchStr.getLength();
822 :
823 : // use the ICU RegexMatcher to find the matches
824 1578 : UErrorCode nIcuErr = U_ZERO_ERROR;
825 3156 : const IcuUniString aSearchTargetStr( (const UChar*)searchStr.getStr(), endPos);
826 1578 : pRegexMatcher->reset( aSearchTargetStr);
827 : // search until there is a valid match
828 : for(;;)
829 : {
830 1578 : if (!lcl_findRegex( pRegexMatcher, startPos, nIcuErr))
831 274 : return aRet;
832 :
833 : // #i118887# ignore zero-length matches e.g. "a*" in "bc"
834 1304 : int nStartOfs = pRegexMatcher->start( nIcuErr);
835 1304 : int nEndOfs = pRegexMatcher->end( nIcuErr);
836 1304 : if( nStartOfs < nEndOfs)
837 1304 : break;
838 : // If the zero-length match is behind the string, do not match it again
839 : // and again until startPos reaches there. A match behind the string is
840 : // a "$" anchor.
841 0 : if (nStartOfs == endPos)
842 0 : break;
843 : // try at next position if there was a zero-length match
844 0 : if( ++startPos >= endPos)
845 0 : return aRet;
846 0 : }
847 :
848 : // extract the result of the search
849 1304 : const int nGroupCount = pRegexMatcher->groupCount();
850 1304 : aRet.subRegExpressions = nGroupCount + 1;
851 1304 : aRet.startOffset.realloc( aRet.subRegExpressions);
852 1304 : aRet.endOffset.realloc( aRet.subRegExpressions);
853 1304 : aRet.startOffset[0] = pRegexMatcher->start( nIcuErr);
854 1304 : aRet.endOffset[0] = pRegexMatcher->end( nIcuErr);
855 1308 : for( int i = 1; i <= nGroupCount; ++i) {
856 4 : aRet.startOffset[i] = pRegexMatcher->start( i, nIcuErr);
857 4 : aRet.endOffset[i] = pRegexMatcher->end( i, nIcuErr);
858 : }
859 :
860 1304 : return aRet;
861 : }
862 :
863 2 : SearchResult TextSearch::RESrchBkwrd( const OUString& searchStr,
864 : sal_Int32 startPos, sal_Int32 endPos )
865 : throw(RuntimeException)
866 : {
867 : // NOTE: for backwards search callers provide startPos/endPos inverted!
868 2 : SearchResult aRet;
869 2 : aRet.subRegExpressions = 0;
870 2 : if( !pRegexMatcher)
871 0 : return aRet;
872 :
873 2 : if( startPos > searchStr.getLength())
874 0 : startPos = searchStr.getLength();
875 :
876 : // use the ICU RegexMatcher to find the matches
877 : // TODO: use ICU's backward searching once it becomes available
878 : // as its replacement using forward search is not as good as the real thing
879 2 : UErrorCode nIcuErr = U_ZERO_ERROR;
880 4 : const IcuUniString aSearchTargetStr( (const UChar*)searchStr.getStr(), startPos);
881 2 : pRegexMatcher->reset( aSearchTargetStr);
882 2 : if (!lcl_findRegex( pRegexMatcher, endPos, nIcuErr))
883 0 : return aRet;
884 :
885 : // find the last match
886 2 : int nLastPos = 0;
887 2 : int nFoundEnd = 0;
888 2 : int nGoodPos = 0, nGoodEnd = 0;
889 2 : bool bFirst = true;
890 2 : do {
891 2 : nLastPos = pRegexMatcher->start( nIcuErr);
892 2 : nFoundEnd = pRegexMatcher->end( nIcuErr);
893 2 : if (nLastPos < nFoundEnd)
894 : {
895 : // remember last non-zero-length match
896 2 : nGoodPos = nLastPos;
897 2 : nGoodEnd = nFoundEnd;
898 : }
899 2 : if( nFoundEnd >= startPos)
900 0 : break;
901 2 : bFirst = false;
902 2 : if( nFoundEnd == nLastPos)
903 0 : ++nFoundEnd;
904 2 : } while( lcl_findRegex( pRegexMatcher, nFoundEnd, nIcuErr));
905 :
906 : // Ignore all zero-length matches except "$" anchor on first match.
907 2 : if (nGoodPos == nGoodEnd)
908 : {
909 0 : if (bFirst && nLastPos == startPos)
910 0 : nGoodPos = nLastPos;
911 : else
912 0 : return aRet;
913 : }
914 :
915 : // find last match again to get its details
916 2 : lcl_findRegex( pRegexMatcher, nGoodPos, nIcuErr);
917 :
918 : // fill in the details of the last match
919 2 : const int nGroupCount = pRegexMatcher->groupCount();
920 2 : aRet.subRegExpressions = nGroupCount + 1;
921 2 : aRet.startOffset.realloc( aRet.subRegExpressions);
922 2 : aRet.endOffset.realloc( aRet.subRegExpressions);
923 : // NOTE: existing users of backward search seem to expect startOfs/endOfs being inverted!
924 2 : aRet.startOffset[0] = pRegexMatcher->end( nIcuErr);
925 2 : aRet.endOffset[0] = pRegexMatcher->start( nIcuErr);
926 6 : for( int i = 1; i <= nGroupCount; ++i) {
927 4 : aRet.startOffset[i] = pRegexMatcher->end( i, nIcuErr);
928 4 : aRet.endOffset[i] = pRegexMatcher->start( i, nIcuErr);
929 : }
930 :
931 2 : return aRet;
932 : }
933 :
934 :
935 :
936 : // search for words phonetically
937 0 : SearchResult TextSearch::ApproxSrchFrwrd( const OUString& searchStr,
938 : sal_Int32 startPos, sal_Int32 endPos )
939 : throw(RuntimeException)
940 : {
941 0 : SearchResult aRet;
942 0 : aRet.subRegExpressions = 0;
943 :
944 0 : if( !xBreak.is() )
945 0 : return aRet;
946 :
947 0 : OUString aWTemp( searchStr );
948 :
949 : sal_Int32 nStt, nEnd;
950 :
951 0 : Boundary aWBnd = xBreak->getWordBoundary( aWTemp, startPos,
952 : aSrchPara.Locale,
953 0 : WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
954 :
955 0 : do
956 : {
957 0 : if( aWBnd.startPos >= endPos )
958 0 : break;
959 0 : nStt = aWBnd.startPos < startPos ? startPos : aWBnd.startPos;
960 0 : nEnd = aWBnd.endPos > endPos ? endPos : aWBnd.endPos;
961 :
962 0 : if( nStt < nEnd &&
963 0 : pWLD->WLD( aWTemp.getStr() + nStt, nEnd - nStt ) <= nLimit )
964 : {
965 0 : aRet.subRegExpressions = 1;
966 0 : aRet.startOffset.realloc( 1 );
967 0 : aRet.startOffset[ 0 ] = nStt;
968 0 : aRet.endOffset.realloc( 1 );
969 0 : aRet.endOffset[ 0 ] = nEnd;
970 0 : break;
971 : }
972 :
973 0 : nStt = nEnd - 1;
974 0 : aWBnd = xBreak->nextWord( aWTemp, nStt, aSrchPara.Locale,
975 0 : WordType::ANYWORD_IGNOREWHITESPACES);
976 0 : } while( aWBnd.startPos != aWBnd.endPos ||
977 0 : (aWBnd.endPos != aWTemp.getLength() && aWBnd.endPos != nEnd) );
978 : // #i50244# aWBnd.endPos != nEnd : in case there is _no_ word (only
979 : // whitespace) in searchStr, getWordBoundary() returned startPos,startPos
980 : // and nextWord() does also => don't loop forever.
981 0 : return aRet;
982 : }
983 :
984 0 : SearchResult TextSearch::ApproxSrchBkwrd( const OUString& searchStr,
985 : sal_Int32 startPos, sal_Int32 endPos )
986 : throw(RuntimeException)
987 : {
988 0 : SearchResult aRet;
989 0 : aRet.subRegExpressions = 0;
990 :
991 0 : if( !xBreak.is() )
992 0 : return aRet;
993 :
994 0 : OUString aWTemp( searchStr );
995 :
996 : sal_Int32 nStt, nEnd;
997 :
998 0 : Boundary aWBnd = xBreak->getWordBoundary( aWTemp, startPos,
999 : aSrchPara.Locale,
1000 0 : WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1001 :
1002 0 : do
1003 : {
1004 0 : if( aWBnd.endPos <= endPos )
1005 0 : break;
1006 0 : nStt = aWBnd.startPos < endPos ? endPos : aWBnd.startPos;
1007 0 : nEnd = aWBnd.endPos > startPos ? startPos : aWBnd.endPos;
1008 :
1009 0 : if( nStt < nEnd &&
1010 0 : pWLD->WLD( aWTemp.getStr() + nStt, nEnd - nStt ) <= nLimit )
1011 : {
1012 0 : aRet.subRegExpressions = 1;
1013 0 : aRet.startOffset.realloc( 1 );
1014 0 : aRet.startOffset[ 0 ] = nEnd;
1015 0 : aRet.endOffset.realloc( 1 );
1016 0 : aRet.endOffset[ 0 ] = nStt;
1017 0 : break;
1018 : }
1019 0 : if( !nStt )
1020 0 : break;
1021 :
1022 0 : aWBnd = xBreak->previousWord( aWTemp, nStt, aSrchPara.Locale,
1023 0 : WordType::ANYWORD_IGNOREWHITESPACES);
1024 0 : } while( aWBnd.startPos != aWBnd.endPos || aWBnd.endPos != aWTemp.getLength() );
1025 0 : return aRet;
1026 : }
1027 :
1028 :
1029 : static const sal_Char cSearchName[] = "com.sun.star.util.TextSearch";
1030 : static const sal_Char cSearchImpl[] = "com.sun.star.util.TextSearch_i18n";
1031 :
1032 20 : static OUString getServiceName_Static()
1033 : {
1034 20 : return OUString::createFromAscii( cSearchName );
1035 : }
1036 :
1037 20 : static OUString getImplementationName_Static()
1038 : {
1039 20 : return OUString::createFromAscii( cSearchImpl );
1040 : }
1041 :
1042 : OUString SAL_CALL
1043 0 : TextSearch::getImplementationName()
1044 : throw( RuntimeException, std::exception )
1045 : {
1046 0 : return getImplementationName_Static();
1047 : }
1048 :
1049 0 : sal_Bool SAL_CALL TextSearch::supportsService(const OUString& rServiceName)
1050 : throw( RuntimeException, std::exception )
1051 : {
1052 0 : return cppu::supportsService(this, rServiceName);
1053 : }
1054 :
1055 : Sequence< OUString > SAL_CALL
1056 0 : TextSearch::getSupportedServiceNames(void) throw( RuntimeException, std::exception )
1057 : {
1058 0 : Sequence< OUString > aRet(1);
1059 0 : aRet[0] = getServiceName_Static();
1060 0 : return aRet;
1061 : }
1062 :
1063 : ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
1064 112 : SAL_CALL TextSearch_CreateInstance(
1065 : const ::com::sun::star::uno::Reference<
1066 : ::com::sun::star::lang::XMultiServiceFactory >& rxMSF )
1067 : {
1068 : return ::com::sun::star::uno::Reference<
1069 : ::com::sun::star::uno::XInterface >(
1070 : (::cppu::OWeakObject*) new TextSearch(
1071 112 : comphelper::getComponentContext( rxMSF ) ) );
1072 : }
1073 :
1074 : extern "C"
1075 : {
1076 : SAL_DLLPUBLIC_EXPORT void* SAL_CALL
1077 20 : i18nsearch_component_getFactory( const sal_Char* sImplementationName,
1078 : void* _pServiceManager,
1079 : SAL_UNUSED_PARAMETER void* )
1080 : {
1081 20 : void* pRet = NULL;
1082 :
1083 : ::com::sun::star::lang::XMultiServiceFactory* pServiceManager =
1084 : reinterpret_cast< ::com::sun::star::lang::XMultiServiceFactory* >
1085 20 : ( _pServiceManager );
1086 : ::com::sun::star::uno::Reference<
1087 20 : ::com::sun::star::lang::XSingleServiceFactory > xFactory;
1088 :
1089 20 : if ( 0 == rtl_str_compare( sImplementationName, cSearchImpl) )
1090 : {
1091 20 : ::com::sun::star::uno::Sequence< OUString > aServiceNames(1);
1092 20 : aServiceNames[0] = getServiceName_Static();
1093 40 : xFactory = ::cppu::createSingleFactory(
1094 : pServiceManager, getImplementationName_Static(),
1095 40 : &TextSearch_CreateInstance, aServiceNames );
1096 : }
1097 :
1098 20 : if ( xFactory.is() )
1099 : {
1100 20 : xFactory->acquire();
1101 20 : pRet = xFactory.get();
1102 : }
1103 :
1104 20 : return pRet;
1105 : }
1106 :
1107 : } // extern "C"
1108 :
1109 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|