1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_unotools.hxx" 26 #include <i18npool/mslangid.hxx> 27 #include <tools/debug.hxx> 28 #ifndef _INTN_HXX //autogen 29 //#include <tools/intn.hxx> 30 #endif 31 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 32 #ifndef _COM_SUN_STAR_UTIL_SEARCHFLAGS_HDL_ 33 #include <com/sun/star/util/SearchFlags.hdl> 34 #endif 35 #include <com/sun/star/i18n/TransliterationModules.hpp> 36 #include <unotools/charclass.hxx> 37 #include <comphelper/processfactory.hxx> 38 #include <unotools/textsearch.hxx> 39 #include <rtl/instance.hxx> 40 41 using namespace ::com::sun::star::util; 42 using namespace ::com::sun::star::uno; 43 using namespace ::com::sun::star::lang; 44 45 // ............................................................................ 46 namespace utl 47 { 48 // ............................................................................ 49 50 SearchParam::SearchParam( const String &rText, 51 SearchType eType, 52 sal_Bool bCaseSensitive, 53 sal_Bool bWrdOnly, 54 sal_Bool bSearchInSel ) 55 { 56 sSrchStr = rText; 57 eSrchType = eType; 58 59 bWordOnly = bWrdOnly; 60 bSrchInSel = bSearchInSel; 61 bCaseSense = bCaseSensitive; 62 63 nTransliterationFlags = 0; 64 65 // Werte fuer "Gewichtete Levenshtein-Distanz" 66 bLEV_Relaxed = sal_True; 67 nLEV_OtherX = 2; 68 nLEV_ShorterY = 1; 69 nLEV_LongerZ = 3; 70 } 71 72 SearchParam::SearchParam( const SearchParam& rParam ) 73 { 74 sSrchStr = rParam.sSrchStr; 75 sReplaceStr = rParam.sReplaceStr; 76 eSrchType = rParam.eSrchType; 77 78 bWordOnly = rParam.bWordOnly; 79 bSrchInSel = rParam.bSrchInSel; 80 bCaseSense = rParam.bCaseSense; 81 82 bLEV_Relaxed = rParam.bLEV_Relaxed; 83 nLEV_OtherX = rParam.nLEV_OtherX; 84 nLEV_ShorterY = rParam.nLEV_ShorterY; 85 nLEV_LongerZ = rParam.nLEV_LongerZ; 86 87 nTransliterationFlags = rParam.nTransliterationFlags; 88 } 89 90 static bool lcl_Equals( const SearchOptions& rSO1, const SearchOptions& rSO2 ) 91 { 92 return rSO1.algorithmType == rSO2.algorithmType && 93 rSO1.searchFlag == rSO2.searchFlag && 94 rSO1.searchString.equals(rSO2.searchString) && 95 rSO1.replaceString.equals(rSO2.replaceString) && 96 rSO1.changedChars == rSO2.changedChars && 97 rSO1.deletedChars == rSO2.deletedChars && 98 rSO1.insertedChars == rSO2.insertedChars && 99 rSO1.Locale.Language == rSO2.Locale.Language && 100 rSO1.Locale.Country == rSO2.Locale.Country && 101 rSO1.Locale.Variant == rSO2.Locale.Variant && 102 rSO1.transliterateFlags == rSO2.transliterateFlags; 103 } 104 105 namespace 106 { 107 struct CachedTextSearch 108 { 109 ::osl::Mutex mutex; 110 ::com::sun::star::util::SearchOptions Options; 111 ::com::sun::star::uno::Reference< ::com::sun::star::util::XTextSearch > xTextSearch; 112 }; 113 114 struct theCachedTextSearch 115 : public rtl::Static< CachedTextSearch, theCachedTextSearch > {}; 116 } 117 118 Reference<XTextSearch> TextSearch::getXTextSearch( const SearchOptions& rPara ) 119 { 120 CachedTextSearch &rCache = theCachedTextSearch::get(); 121 122 osl::MutexGuard aGuard(rCache.mutex); 123 124 if ( lcl_Equals(rCache.Options, rPara) ) 125 return rCache.xTextSearch; 126 127 try 128 { 129 Reference< XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); 130 rCache.xTextSearch.set( xMSF->createInstance( 131 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 132 "com.sun.star.util.TextSearch" ) ) ), UNO_QUERY_THROW ); 133 rCache.xTextSearch->setOptions( rPara ); 134 rCache.Options = rPara; 135 } 136 catch ( Exception& ) 137 { 138 DBG_ERRORFILE( "TextSearch ctor: Exception caught!" ); 139 } 140 return rCache.xTextSearch; 141 } 142 143 TextSearch::TextSearch(const SearchParam & rParam, LanguageType eLang ) 144 { 145 if( LANGUAGE_NONE == eLang ) 146 eLang = LANGUAGE_SYSTEM; 147 ::com::sun::star::lang::Locale aLocale( 148 MsLangId::convertLanguageToLocale( LanguageType(eLang))); 149 150 Init( rParam, aLocale); 151 } 152 153 TextSearch::TextSearch(const SearchParam & rParam, const CharClass& rCClass ) 154 { 155 Init( rParam, rCClass.getLocale() ); 156 } 157 158 TextSearch::TextSearch( const SearchOptions& rPara ) 159 { 160 xTextSearch = getXTextSearch( rPara ); 161 } 162 163 void TextSearch::Init( const SearchParam & rParam, 164 const ::com::sun::star::lang::Locale& rLocale ) 165 { 166 // convert SearchParam to the UNO SearchOptions 167 SearchOptions aSOpt; 168 169 switch( rParam.GetSrchType() ) 170 { 171 case SearchParam::SRCH_REGEXP: 172 aSOpt.algorithmType = SearchAlgorithms_REGEXP; 173 if( rParam.IsSrchInSelection() ) 174 aSOpt.searchFlag |= SearchFlags::REG_NOT_BEGINOFLINE | 175 SearchFlags::REG_NOT_ENDOFLINE; 176 break; 177 178 case SearchParam::SRCH_LEVDIST: 179 aSOpt.algorithmType = SearchAlgorithms_APPROXIMATE; 180 aSOpt.changedChars = rParam.GetLEVOther(); 181 aSOpt.deletedChars = rParam.GetLEVLonger(); 182 aSOpt.insertedChars = rParam.GetLEVShorter(); 183 if( rParam.IsSrchRelaxed() ) 184 aSOpt.searchFlag |= SearchFlags::LEV_RELAXED; 185 break; 186 187 // case SearchParam::SRCH_NORMAL: 188 default: 189 aSOpt.algorithmType = SearchAlgorithms_ABSOLUTE; 190 if( rParam.IsSrchWordOnly() ) 191 aSOpt.searchFlag |= SearchFlags::NORM_WORD_ONLY; 192 break; 193 } 194 aSOpt.searchString = rParam.GetSrchStr(); 195 aSOpt.replaceString = rParam.GetReplaceStr(); 196 aSOpt.Locale = rLocale; 197 aSOpt.transliterateFlags = rParam.GetTransliterationFlags(); 198 if( !rParam.IsCaseSensitive() ) 199 { 200 aSOpt.searchFlag |= SearchFlags::ALL_IGNORE_CASE; 201 aSOpt.transliterateFlags |= ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE; 202 } 203 204 xTextSearch = getXTextSearch( aSOpt ); 205 } 206 207 void TextSearch::SetLocale( const ::com::sun::star::util::SearchOptions& rOptions, 208 const ::com::sun::star::lang::Locale& rLocale ) 209 { 210 // convert SearchParam to the UNO SearchOptions 211 SearchOptions aSOpt( rOptions ); 212 aSOpt.Locale = rLocale; 213 214 xTextSearch = getXTextSearch( aSOpt ); 215 } 216 217 218 TextSearch::~TextSearch() 219 { 220 } 221 222 /* 223 * Die allgemeinen Methoden zu Suchen. Diese rufen dann die entpsrecheden 224 * Methoden fuer die normale Suche oder der Suche nach Regular-Expressions 225 * ueber die MethodenPointer auf. 226 */ 227 #if defined _MSC_VER 228 #pragma optimize("", off) 229 #pragma warning(push) 230 #pragma warning(disable: 4748) 231 #endif 232 int TextSearch::SearchFrwrd( const String & rStr, xub_StrLen* pStart, 233 xub_StrLen* pEnde, SearchResult* pRes ) 234 { 235 int nRet = 0; 236 try 237 { 238 if( xTextSearch.is() ) 239 { 240 SearchResult aRet( xTextSearch->searchForward( 241 rStr, *pStart, *pEnde )); 242 if( aRet.subRegExpressions > 0 ) 243 { 244 nRet = 1; 245 // the XTextsearch returns in startOffset the higher position 246 // and the endposition is allways exclusive. 247 // The caller of this function will have in startPos the 248 // lower pos. and end 249 *pStart = (xub_StrLen)aRet.startOffset[ 0 ]; 250 *pEnde = (xub_StrLen)aRet.endOffset[ 0 ]; 251 if( pRes ) 252 *pRes = aRet; 253 } 254 } 255 } 256 catch ( Exception& ) 257 { 258 DBG_ERRORFILE( "SearchForward: Exception caught!" ); 259 } 260 return nRet; 261 } 262 263 int TextSearch::SearchBkwrd( const String & rStr, xub_StrLen* pStart, 264 xub_StrLen* pEnde, SearchResult* pRes ) 265 { 266 int nRet = 0; 267 try 268 { 269 if( xTextSearch.is() ) 270 { 271 SearchResult aRet( xTextSearch->searchBackward( 272 rStr, *pStart, *pEnde )); 273 if( aRet.subRegExpressions ) 274 { 275 nRet = 1; 276 // the XTextsearch returns in startOffset the higher position 277 // and the endposition is allways exclusive. 278 // The caller of this function will have in startPos the 279 // lower pos. and end 280 *pEnde = (xub_StrLen)aRet.startOffset[ 0 ]; 281 *pStart = (xub_StrLen)aRet.endOffset[ 0 ]; 282 if( pRes ) 283 *pRes = aRet; 284 } 285 } 286 } 287 catch ( Exception& ) 288 { 289 DBG_ERRORFILE( "SearchBackward: Exception caught!" ); 290 } 291 return nRet; 292 } 293 294 void TextSearch::ReplaceBackReferences( String& rReplaceStr, const String &rStr, const SearchResult& rResult ) 295 { 296 if( rResult.subRegExpressions > 0 ) 297 { 298 String sTab( '\t' ); 299 sal_Unicode sSrchChrs[] = {'\\', '&', '$', 0}; 300 String sTmp; 301 xub_StrLen nPos = 0; 302 sal_Unicode sFndChar; 303 while( STRING_NOTFOUND != ( nPos = rReplaceStr.SearchChar( sSrchChrs, nPos )) ) 304 { 305 if( rReplaceStr.GetChar( nPos ) == '&') 306 { 307 sal_uInt16 nStart = (sal_uInt16)(rResult.startOffset[0]); 308 sal_uInt16 nLength = (sal_uInt16)(rResult.endOffset[0] - rResult.startOffset[0]); 309 rReplaceStr.Erase( nPos, 1 ); // delete ampersand 310 // replace by found string 311 rReplaceStr.Insert( rStr, nStart, nLength, nPos ); 312 // jump over 313 nPos = nPos + nLength; 314 } 315 else if( rReplaceStr.GetChar( nPos ) == '$') 316 { 317 if( nPos + 1 < rReplaceStr.Len()) 318 { 319 sFndChar = rReplaceStr.GetChar( nPos + 1 ); 320 switch(sFndChar) 321 { // placeholder for a backward reference? 322 case '0': 323 case '1': 324 case '2': 325 case '3': 326 case '4': 327 case '5': 328 case '6': 329 case '7': 330 case '8': 331 case '9': 332 { 333 rReplaceStr.Erase( nPos, 2 ); // delete both 334 int i = sFndChar - '0'; // index 335 if(i < rResult.subRegExpressions) 336 { 337 sal_uInt16 nSttReg = (sal_uInt16)(rResult.startOffset[i]); 338 sal_uInt16 nRegLen = (sal_uInt16)(rResult.endOffset[i]); 339 if( nRegLen > nSttReg ) 340 nRegLen = nRegLen - nSttReg; 341 else 342 { 343 nRegLen = nSttReg - nRegLen; 344 nSttReg = (sal_uInt16)(rResult.endOffset[i]); 345 } 346 // Copy reference from found string 347 sTmp = rStr.Copy((sal_uInt16)nSttReg, (sal_uInt16)nRegLen); 348 // insert 349 rReplaceStr.Insert( sTmp, nPos ); 350 // and step over 351 nPos = nPos + sTmp.Len(); 352 } 353 } 354 break; 355 default: 356 nPos += 2; // leave both chars unchanged 357 break; 358 } 359 } 360 else 361 ++nPos; 362 } 363 else 364 { 365 // at least another character? 366 if( nPos + 1 < rReplaceStr.Len()) 367 { 368 sFndChar = rReplaceStr.GetChar( nPos + 1 ); 369 switch(sFndChar) 370 { 371 case '\\': 372 case '&': 373 case '$': 374 rReplaceStr.Erase( nPos, 1 ); 375 nPos++; 376 break; 377 case 't': 378 rReplaceStr.Erase( nPos, 2 ); // delete both 379 rReplaceStr.Insert( sTab, nPos ); // insert tabulator 380 nPos++; // step over 381 break; 382 default: 383 nPos += 2; // ignore both characters 384 break; 385 } 386 } 387 else 388 ++nPos; 389 } 390 } 391 } 392 } 393 394 395 #if defined _MSC_VER 396 #pragma optimize("", on) 397 #pragma warning(pop) 398 #endif 399 400 // ............................................................................ 401 } // namespace utl 402 // ............................................................................ 403 404