LCOV - code coverage report
Current view: top level - editeng/source/misc - svxacorr.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 341 1447 23.6 %
Date: 2014-11-03 Functions: 33 97 34.0 %
Legend: Lines: hit not hit

          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 <com/sun/star/io/XStream.hpp>
      21             : #include <com/sun/star/lang/Locale.hpp>
      22             : #include <tools/urlobj.hxx>
      23             : #include <i18nlangtag/mslangid.hxx>
      24             : #include <vcl/svapp.hxx>
      25             : #include <vcl/settings.hxx>
      26             : #include <sot/storinfo.hxx>
      27             : #include <svl/fstathelper.hxx>
      28             : #include <svtools/helpopt.hxx>
      29             : #include <svl/urihelper.hxx>
      30             : #include <unotools/charclass.hxx>
      31             : #include <com/sun/star/i18n/UnicodeType.hpp>
      32             : #include <unotools/collatorwrapper.hxx>
      33             : #include <com/sun/star/i18n/CollatorOptions.hpp>
      34             : #include <com/sun/star/i18n/UnicodeScript.hpp>
      35             : #include <com/sun/star/i18n/OrdinalSuffix.hpp>
      36             : #include <unotools/localedatawrapper.hxx>
      37             : #include <unotools/transliterationwrapper.hxx>
      38             : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      39             : #include <com/sun/star/io/XActiveDataSource.hpp>
      40             : #include <comphelper/processfactory.hxx>
      41             : #include <comphelper/storagehelper.hxx>
      42             : #include <comphelper/string.hxx>
      43             : #include <editeng/editids.hrc>
      44             : #include <sot/storage.hxx>
      45             : #include <editeng/udlnitem.hxx>
      46             : #include <editeng/wghtitem.hxx>
      47             : #include <editeng/escapementitem.hxx>
      48             : #include <editeng/svxacorr.hxx>
      49             : #include <editeng/unolingu.hxx>
      50             : #include "vcl/window.hxx"
      51             : #include <helpid.hrc>
      52             : #include <com/sun/star/xml/sax/InputSource.hpp>
      53             : #include <com/sun/star/xml/sax/FastParser.hpp>
      54             : #include <com/sun/star/xml/sax/FastToken.hpp>
      55             : #include <com/sun/star/xml/sax/Writer.hpp>
      56             : #include <com/sun/star/xml/sax/FastTokenHandler.hpp>
      57             : #include <unotools/streamwrap.hxx>
      58             : #include <SvXMLAutoCorrectImport.hxx>
      59             : #include <SvXMLAutoCorrectExport.hxx>
      60             : #include <SvXMLAutoCorrectTokenHandler.hxx>
      61             : #include <ucbhelper/content.hxx>
      62             : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
      63             : #include <com/sun/star/ucb/TransferInfo.hpp>
      64             : #include <com/sun/star/ucb/NameClash.hpp>
      65             : #include <xmloff/xmltoken.hxx>
      66             : #include <vcl/help.hxx>
      67             : 
      68             : using namespace ::com::sun::star::ucb;
      69             : using namespace ::com::sun::star::uno;
      70             : using namespace ::com::sun::star::xml::sax;
      71             : using namespace ::com::sun::star;
      72             : using namespace ::xmloff::token;
      73             : using namespace ::utl;
      74             : 
      75             : static const int C_NONE             = 0x00;
      76             : static const int C_FULL_STOP        = 0x01;
      77             : static const int C_EXCLAMATION_MARK = 0x02;
      78             : static const int C_QUESTION_MARK    = 0x04;
      79             : static const sal_Unicode cNonBreakingSpace = 0xA0;
      80             : 
      81             : static const sal_Char pXMLImplWrdStt_ExcptLstStr[] = "WordExceptList.xml";
      82             : static const sal_Char pXMLImplCplStt_ExcptLstStr[] = "SentenceExceptList.xml";
      83             : static const sal_Char pXMLImplAutocorr_ListStr[]   = "DocumentList.xml";
      84             : 
      85             : static const sal_Char
      86             :     /* also at these beginnings - Brackets and all kinds of begin characters */
      87             :     sImplSttSkipChars[] = "\"\'([{\x83\x84\x89\x91\x92\x93\x94",
      88             :     /* also at these ends - Brackets and all kinds of begin characters */
      89             :     sImplEndSkipChars[] = "\"\')]}\x83\x84\x89\x91\x92\x93\x94";
      90             : 
      91             : // These characters are allowed in words: (for FnCptlSttSntnc)
      92             : static const sal_Char sImplWordChars[] = "-'";
      93             : 
      94             : OUString EncryptBlockName_Imp(const OUString& rName);
      95             : 
      96           0 : TYPEINIT0(SvxAutoCorrect)
      97             : 
      98             : typedef SvxAutoCorrectLanguageLists* SvxAutoCorrectLanguageListsPtr;
      99             : 
     100          44 : static inline bool IsWordDelim( const sal_Unicode c )
     101             : {
     102          44 :     return ' ' == c || '\t' == c || 0x0a == c ||
     103          88 :             cNonBreakingSpace == c || 0x2011 == c || 0x1 == c;
     104             : }
     105             : 
     106           8 : static inline bool IsLowerLetter( sal_Int32 nCharType )
     107             : {
     108          16 :     return CharClass::isLetterType( nCharType ) &&
     109          16 :             0 == ( ::com::sun::star::i18n::KCharacterType::UPPER & nCharType);
     110             : }
     111             : 
     112          20 : static inline bool IsUpperLetter( sal_Int32 nCharType )
     113             : {
     114          40 :     return CharClass::isLetterType( nCharType ) &&
     115          40 :             0 == ( ::com::sun::star::i18n::KCharacterType::LOWER & nCharType);
     116             : }
     117             : 
     118           4 : bool lcl_IsUnsupportedUnicodeChar( CharClass& rCC, const OUString& rTxt,
     119             :                                    sal_Int32 nStt, sal_Int32 nEnd )
     120             : {
     121          40 :     for( ; nStt < nEnd; ++nStt )
     122             :     {
     123          36 :         short nScript = rCC.getScript( rTxt, nStt );
     124          36 :         switch( nScript )
     125             :         {
     126             :             case ::com::sun::star::i18n::UnicodeScript_kCJKRadicalsSupplement:
     127             :             case ::com::sun::star::i18n::UnicodeScript_kHangulJamo:
     128             :             case ::com::sun::star::i18n::UnicodeScript_kCJKSymbolPunctuation:
     129             :             case ::com::sun::star::i18n::UnicodeScript_kHiragana:
     130             :             case ::com::sun::star::i18n::UnicodeScript_kKatakana:
     131             :             case ::com::sun::star::i18n::UnicodeScript_kHangulCompatibilityJamo:
     132             :             case ::com::sun::star::i18n::UnicodeScript_kEnclosedCJKLetterMonth:
     133             :             case ::com::sun::star::i18n::UnicodeScript_kCJKCompatibility:
     134             :             case ::com::sun::star::i18n::UnicodeScript_k_CJKUnifiedIdeographsExtensionA:
     135             :             case ::com::sun::star::i18n::UnicodeScript_kCJKUnifiedIdeograph:
     136             :             case ::com::sun::star::i18n::UnicodeScript_kHangulSyllable:
     137             :             case ::com::sun::star::i18n::UnicodeScript_kCJKCompatibilityIdeograph:
     138             :             case ::com::sun::star::i18n::UnicodeScript_kHalfwidthFullwidthForm:
     139           0 :                 return true;
     140             :             default: ; //do nothing
     141             :         }
     142             :     }
     143           4 :     return false;
     144             : }
     145             : 
     146           4 : static bool lcl_IsSymbolChar( CharClass& rCC, const OUString& rTxt,
     147             :                                   sal_Int32 nStt, sal_Int32 nEnd )
     148             : {
     149          40 :     for( ; nStt < nEnd; ++nStt )
     150             :     {
     151          36 :         if( ::com::sun::star::i18n::UnicodeType::PRIVATE_USE ==
     152          36 :                 rCC.getType( rTxt, nStt ))
     153           0 :             return true;
     154             :     }
     155           4 :     return false;
     156             : }
     157             : 
     158          20 : static bool lcl_IsInAsciiArr( const sal_Char* pArr, const sal_Unicode c )
     159             : {
     160          20 :     bool bRet = false;
     161         216 :     for( ; *pArr; ++pArr )
     162         198 :         if( *pArr == c )
     163             :         {
     164           2 :             bRet = true;
     165           2 :             break;
     166             :         }
     167          20 :     return bRet;
     168             : }
     169             : 
     170           6 : SvxAutoCorrDoc::~SvxAutoCorrDoc()
     171             : {
     172           6 : }
     173             : 
     174             : // Called by the functions:
     175             : //  - FnCptlSttWrd
     176             : //  - FnCptlSttSntnc
     177             : // after the exchange of characters. Then the words, if necessary, can be inserted
     178             : // into the exception list.
     179           8 : void SvxAutoCorrDoc::SaveCpltSttWord( sal_uLong, sal_Int32, const OUString&,
     180             :                                         sal_Unicode )
     181             : {
     182           8 : }
     183             : 
     184           4 : LanguageType SvxAutoCorrDoc::GetLanguage( sal_Int32, bool ) const
     185             : {
     186           4 :     return LANGUAGE_SYSTEM;
     187             : }
     188             : 
     189          90 : static const LanguageTag& GetAppLang()
     190             : {
     191          90 :     return Application::GetSettings().GetLanguageTag();
     192             : }
     193           0 : static LocaleDataWrapper& GetLocaleDataWrapper( sal_uInt16 nLang )
     194             : {
     195           0 :     static LocaleDataWrapper aLclDtWrp( GetAppLang() );
     196           0 :     LanguageTag aLcl( nLang );
     197           0 :     const LanguageTag& rLcl = aLclDtWrp.getLoadedLanguageTag();
     198           0 :     if( aLcl != rLcl )
     199           0 :         aLclDtWrp.setLanguageTag( aLcl );
     200           0 :     return aLclDtWrp;
     201             : }
     202           0 : static TransliterationWrapper& GetIgnoreTranslWrapper()
     203             : {
     204             :     static int bIsInit = 0;
     205             :     static TransliterationWrapper aWrp( ::comphelper::getProcessComponentContext(),
     206             :                 ::com::sun::star::i18n::TransliterationModules_IGNORE_KANA |
     207           0 :                 ::com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH );
     208           0 :     if( !bIsInit )
     209             :     {
     210           0 :         aWrp.loadModuleIfNeeded( GetAppLang().getLanguageType() );
     211           0 :         bIsInit = 1;
     212             :     }
     213           0 :     return aWrp;
     214             : }
     215           0 : static CollatorWrapper& GetCollatorWrapper()
     216             : {
     217             :     static int bIsInit = 0;
     218           0 :     static CollatorWrapper aCollWrp( ::comphelper::getProcessComponentContext() );
     219           0 :     if( !bIsInit )
     220             :     {
     221           0 :         aCollWrp.loadDefaultCollator( GetAppLang().getLocale(), 0 );
     222           0 :         bIsInit = 1;
     223             :     }
     224           0 :     return aCollWrp;
     225             : }
     226             : 
     227         178 : static void lcl_ClearTable(boost::ptr_map<LanguageTag, SvxAutoCorrectLanguageLists>& rLangTable)
     228             : {
     229         178 :     rLangTable.clear();
     230         178 : }
     231             : 
     232          40 : bool SvxAutoCorrect::IsAutoCorrectChar( sal_Unicode cChar )
     233             : {
     234          40 :     return  cChar == '\0' || cChar == '\t' || cChar == 0x0a ||
     235          40 :             cChar == ' '  || cChar == '\'' || cChar == '\"' ||
     236          40 :             cChar == '*'  || cChar == '_'  || cChar == '%' ||
     237          40 :             cChar == '.'  || cChar == ','  || cChar == ';' ||
     238          40 :             cChar == ':'  || cChar == '?' || cChar == '!' ||
     239          78 :             cChar == '/'  || cChar == '-';
     240             : }
     241             : 
     242           6 : bool SvxAutoCorrect::NeedsHardspaceAutocorr( sal_Unicode cChar )
     243             : {
     244           6 :     return cChar == '%' || cChar == ';' || cChar == ':'  || cChar == '?' || cChar == '!' ||
     245           6 :         cChar == '/' /*case for the urls exception*/;
     246             : }
     247             : 
     248          90 : long SvxAutoCorrect::GetDefaultFlags()
     249             : {
     250             :     long nRet = Autocorrect
     251             :                     | CptlSttSntnc
     252             :                     | CptlSttWrd
     253             :                     | ChgOrdinalNumber
     254             :                     | ChgToEnEmDash
     255             :                     | AddNonBrkSpace
     256             :                     | ChgWeightUnderl
     257             :                     | SetINetAttr
     258             :                     | ChgQuotes
     259             :                     | SaveWordCplSttLst
     260             :                     | SaveWordWrdSttLst
     261          90 :                     | CorrectCapsLock;
     262          90 :     LanguageType eLang = GetAppLang().getLanguageType();
     263          90 :     switch( eLang )
     264             :     {
     265             :     case LANGUAGE_ENGLISH:
     266             :     case LANGUAGE_ENGLISH_US:
     267             :     case LANGUAGE_ENGLISH_UK:
     268             :     case LANGUAGE_ENGLISH_AUS:
     269             :     case LANGUAGE_ENGLISH_CAN:
     270             :     case LANGUAGE_ENGLISH_NZ:
     271             :     case LANGUAGE_ENGLISH_EIRE:
     272             :     case LANGUAGE_ENGLISH_SAFRICA:
     273             :     case LANGUAGE_ENGLISH_JAMAICA:
     274             :     case LANGUAGE_ENGLISH_CARRIBEAN:
     275          90 :         nRet &= ~(ChgQuotes|ChgSglQuotes);
     276          90 :         break;
     277             :     }
     278          90 :     return nRet;
     279             : }
     280             : 
     281             : 
     282          90 : SvxAutoCorrect::SvxAutoCorrect( const OUString& rShareAutocorrFile,
     283             :                                 const OUString& rUserAutocorrFile )
     284             :     : sShareAutoCorrFile( rShareAutocorrFile )
     285             :     , sUserAutoCorrFile( rUserAutocorrFile )
     286          90 :     , pLangTable( new boost::ptr_map<LanguageTag, SvxAutoCorrectLanguageLists> )
     287             :     , pCharClass( 0 )
     288             :     , bRunNext( false )
     289             :     , eCharClassLang( LANGUAGE_DONTKNOW )
     290          90 :     , nFlags(SvxAutoCorrect::GetDefaultFlags())
     291             :     , cStartDQuote( 0 )
     292             :     , cEndDQuote( 0 )
     293             :     , cStartSQuote( 0 )
     294             :     , cEndSQuote( 0 )
     295             :     , cEmDash( 0x2014 )
     296         270 :     , cEnDash( 0x2013)
     297             : {
     298          90 : }
     299             : 
     300          88 : SvxAutoCorrect::SvxAutoCorrect( const SvxAutoCorrect& rCpy )
     301             :     : sShareAutoCorrFile( rCpy.sShareAutoCorrFile )
     302             :     , sUserAutoCorrFile( rCpy.sUserAutoCorrFile )
     303             :     , aSwFlags( rCpy.aSwFlags )
     304          88 :     , pLangTable( new boost::ptr_map<LanguageTag, SvxAutoCorrectLanguageLists> )
     305             :     , pCharClass( 0 )
     306             :     , bRunNext( false )
     307             :     , eCharClassLang(rCpy.eCharClassLang)
     308          88 :     , nFlags( rCpy.nFlags & ~(ChgWordLstLoad|CplSttLstLoad|WrdSttLstLoad))
     309             :     , cStartDQuote( rCpy.cStartDQuote )
     310             :     , cEndDQuote( rCpy.cEndDQuote )
     311             :     , cStartSQuote( rCpy.cStartSQuote )
     312             :     , cEndSQuote( rCpy.cEndSQuote )
     313             :     , cEmDash( rCpy.cEmDash )
     314         264 :     , cEnDash( rCpy.cEnDash )
     315             : {
     316          88 : }
     317             : 
     318             : 
     319         444 : SvxAutoCorrect::~SvxAutoCorrect()
     320             : {
     321         178 :     lcl_ClearTable(*pLangTable);
     322         178 :     delete pLangTable;
     323         178 :     delete pCharClass;
     324         266 : }
     325             : 
     326           4 : void SvxAutoCorrect::_GetCharClass( LanguageType eLang )
     327             : {
     328           4 :     delete pCharClass;
     329           4 :     pCharClass = new CharClass( LanguageTag( eLang));
     330           4 :     eCharClassLang = eLang;
     331           4 : }
     332             : 
     333         176 : void SvxAutoCorrect::SetAutoCorrFlag( long nFlag, bool bOn )
     334             : {
     335         176 :     long nOld = nFlags;
     336          88 :     nFlags = bOn ? nFlags | nFlag
     337         264 :                  : nFlags & ~nFlag;
     338             : 
     339         176 :     if( !bOn )
     340             :     {
     341          88 :         if( (nOld & CptlSttSntnc) != (nFlags & CptlSttSntnc) )
     342           0 :             nFlags &= ~CplSttLstLoad;
     343          88 :         if( (nOld & CptlSttWrd) != (nFlags & CptlSttWrd) )
     344           0 :             nFlags &= ~WrdSttLstLoad;
     345          88 :         if( (nOld & Autocorrect) != (nFlags & Autocorrect) )
     346           0 :             nFlags &= ~ChgWordLstLoad;
     347             :     }
     348         176 : }
     349             : 
     350             : 
     351             :     // Two capital letters at the beginning of word?
     352           4 : bool SvxAutoCorrect::FnCptlSttWrd( SvxAutoCorrDoc& rDoc, const OUString& rTxt,
     353             :                                     sal_Int32 nSttPos, sal_Int32 nEndPos,
     354             :                                     LanguageType eLang )
     355             : {
     356           4 :     bool bRet = false;
     357           4 :     CharClass& rCC = GetCharClass( eLang );
     358             : 
     359             :     // Delete all non alphanumeric. Test the characters at the beginning/end of
     360             :     // the word ( recognizes: "(min.", "/min.", and so on.)
     361           4 :     for( ; nSttPos < nEndPos; ++nSttPos )
     362           4 :         if( rCC.isLetterNumeric( rTxt, nSttPos ))
     363           4 :             break;
     364           4 :     for( ; nSttPos < nEndPos; --nEndPos )
     365           4 :         if( rCC.isLetterNumeric( rTxt, nEndPos - 1 ))
     366           4 :             break;
     367             : 
     368             :     // Is the word a compounded word separated by delimiters?
     369             :     // If so, keep track of all delimiters so each constituent
     370             :     // word can be checked for two initial capital letters.
     371           4 :     std::deque<sal_Int32> aDelimiters;
     372             : 
     373             :     // Always check for two capitals at the beginning
     374             :     // of the entire word, so start at nSttPos.
     375           4 :     aDelimiters.push_back(nSttPos);
     376             : 
     377             :     // Find all compound word delimiters
     378          40 :     for (sal_Int32 n = nSttPos; n < nEndPos; ++n)
     379             :     {
     380          36 :         if (IsAutoCorrectChar(rTxt[ n ]))
     381             :         {
     382           4 :             aDelimiters.push_back( n + 1 ); // Get position of char after delimiter
     383             :         }
     384             :     }
     385             : 
     386             :     // Decide where to put the terminating delimiter.
     387             :     // If the last AutoCorrect char was a newline, then the AutoCorrect
     388             :     // char will not be included in rTxt.
     389             :     // If the last AutoCorrect char was not a newline, then the AutoCorrect
     390             :     // character will be the last character in rTxt.
     391           4 :     if (!IsAutoCorrectChar(rTxt[nEndPos-1]))
     392           4 :         aDelimiters.push_back(nEndPos);
     393             : 
     394             :     // Iterate through the word and all words that compose it.
     395             :     // Two capital letters at the beginning of word?
     396          12 :     for (size_t nI = 0; nI < aDelimiters.size() - 1; ++nI)
     397             :     {
     398           8 :         nSttPos = aDelimiters[nI];
     399           8 :         nEndPos = aDelimiters[nI + 1];
     400             : 
     401          24 :         if( nSttPos+2 < nEndPos &&
     402          24 :             IsUpperLetter( rCC.getCharacterType( rTxt, nSttPos )) &&
     403          24 :             IsUpperLetter( rCC.getCharacterType( rTxt, ++nSttPos )) &&
     404             :             // Is the third character a lower case
     405          16 :             IsLowerLetter( rCC.getCharacterType( rTxt, nSttPos +1 )) &&
     406             :             // Do not replace special attributes
     407          24 :             0x1 != rTxt[ nSttPos ] && 0x2 != rTxt[ nSttPos ])
     408             :         {
     409             :             // test if the word is in an exception list
     410           8 :             OUString sWord( rTxt.copy( nSttPos - 1, nEndPos - nSttPos + 1 ));
     411           8 :             if( !FindInWrdSttExceptList(eLang, sWord) )
     412             :             {
     413             :                 // Check that word isn't correctly spelled before correcting:
     414             :                 ::com::sun::star::uno::Reference<
     415             :                     ::com::sun::star::linguistic2::XSpellChecker1 > xSpeller =
     416           8 :                     SvxGetSpellChecker();
     417           8 :                 if( xSpeller->hasLanguage(eLang) )
     418             :                 {
     419           0 :                     Sequence< ::com::sun::star::beans::PropertyValue > aEmptySeq;
     420           0 :                     if (!xSpeller->spell(sWord, eLang, aEmptySeq).is())
     421             :                     {
     422           0 :                         return false;
     423           0 :                     }
     424             :                 }
     425           8 :                 sal_Unicode cSave = rTxt[ nSttPos ];
     426          16 :                 OUString sChar( cSave );
     427           8 :                 sChar = rCC.lowercase( sChar );
     428           8 :                 if( sChar[0] != cSave && rDoc.ReplaceRange( nSttPos, 1, sChar ))
     429             :                 {
     430           8 :                     if( SaveWordWrdSttLst & nFlags )
     431           8 :                         rDoc.SaveCpltSttWord( CptlSttWrd, nSttPos, sWord, cSave );
     432           8 :                     bRet = true;
     433           8 :                 }
     434           8 :             }
     435             :         }
     436             :     }
     437           4 :     return bRet;
     438             : }
     439             : 
     440             : 
     441           4 : bool SvxAutoCorrect::FnChgOrdinalNumber(
     442             :                                 SvxAutoCorrDoc& rDoc, const OUString& rTxt,
     443             :                                 sal_Int32 nSttPos, sal_Int32 nEndPos,
     444             :                                 LanguageType eLang )
     445             : {
     446             : // 1st, 2nd, 3rd, 4 - 0th
     447             : // 201th or 201st
     448             : // 12th or 12nd
     449           4 :     CharClass& rCC = GetCharClass( eLang );
     450           4 :     bool bChg = false;
     451             : 
     452           4 :     for( ; nSttPos < nEndPos; ++nSttPos )
     453           4 :         if( !lcl_IsInAsciiArr( sImplSttSkipChars, rTxt[ nSttPos ] ))
     454           4 :             break;
     455           4 :     for( ; nSttPos < nEndPos; --nEndPos )
     456           4 :         if( !lcl_IsInAsciiArr( sImplEndSkipChars, rTxt[ nEndPos - 1 ] ))
     457           4 :             break;
     458             : 
     459             : 
     460             :     // Get the last number in the string to check
     461           4 :     sal_Int32 nNumEnd = nEndPos;
     462           4 :     bool foundEnd = false;
     463           4 :     bool validNumber = true;
     464           4 :     sal_Int32 i = nEndPos;
     465             : 
     466          44 :     while ( i > nSttPos )
     467             :     {
     468          36 :         i--;
     469          36 :         bool isDigit = rCC.isDigit( rTxt, i );
     470          36 :         if ( foundEnd )
     471           0 :             validNumber |= isDigit;
     472             : 
     473          36 :         if ( isDigit && !foundEnd )
     474             :         {
     475           0 :             foundEnd = true;
     476           0 :             nNumEnd = i;
     477             :         }
     478             :     }
     479             : 
     480           4 :     if ( foundEnd && validNumber ) {
     481           0 :         sal_Int32 nNum = rTxt.copy( nSttPos, nNumEnd - nSttPos + 1 ).toInt32( );
     482             : 
     483             :         // Check if the characters after that number correspond to the ordinal suffix
     484             :         uno::Reference< i18n::XOrdinalSuffix > xOrdSuffix
     485           0 :                 = i18n::OrdinalSuffix::create( comphelper::getProcessComponentContext() );
     486             : 
     487           0 :         uno::Sequence< OUString > aSuffixes = xOrdSuffix->getOrdinalSuffix( nNum, rCC.getLanguageTag().getLocale( ) );
     488           0 :         for ( sal_Int32 nSuff = 0; nSuff < aSuffixes.getLength(); nSuff++ )
     489             :         {
     490           0 :             OUString sSuffix( aSuffixes[ nSuff ] );
     491           0 :             OUString sEnd = rTxt.copy( nNumEnd + 1, nEndPos - nNumEnd - 1 );
     492             : 
     493           0 :             if ( sSuffix == sEnd )
     494             :             {
     495             :                 // Check if the ordinal suffix has to be set as super script
     496           0 :                 if ( rCC.isLetter( sSuffix ) )
     497             :                 {
     498             :                     // Do the change
     499             :                     SvxEscapementItem aSvxEscapementItem( DFLT_ESC_AUTO_SUPER,
     500           0 :                                                         DFLT_ESC_PROP, SID_ATTR_CHAR_ESCAPEMENT );
     501             :                     rDoc.SetAttr( nNumEnd + 1 , nEndPos,
     502             :                                     SID_ATTR_CHAR_ESCAPEMENT,
     503           0 :                                     aSvxEscapementItem);
     504             :                 }
     505             :             }
     506           0 :         }
     507             :     }
     508           4 :     return bChg;
     509             : }
     510             : 
     511             : 
     512           4 : bool SvxAutoCorrect::FnChgToEnEmDash(
     513             :                                 SvxAutoCorrDoc& rDoc, const OUString& rTxt,
     514             :                                 sal_Int32 nSttPos, sal_Int32 nEndPos,
     515             :                                 LanguageType eLang )
     516             : {
     517           4 :     bool bRet = false;
     518           4 :     CharClass& rCC = GetCharClass( eLang );
     519           4 :     if (eLang == LANGUAGE_SYSTEM)
     520           0 :         eLang = GetAppLang().getLanguageType();
     521           4 :     bool bAlwaysUseEmDash = (cEmDash && (eLang == LANGUAGE_RUSSIAN || eLang == LANGUAGE_UKRAINIAN));
     522             : 
     523             :     // replace " - " or " --" with "enDash"
     524           4 :     if( cEnDash && 1 < nSttPos && 1 <= nEndPos - nSttPos )
     525             :     {
     526           0 :         sal_Unicode cCh = rTxt[ nSttPos ];
     527           0 :         if( '-' == cCh )
     528             :         {
     529           0 :             if( ' ' == rTxt[ nSttPos-1 ] &&
     530           0 :                 '-' == rTxt[ nSttPos+1 ])
     531             :             {
     532             :                 sal_Int32 n;
     533           0 :                 for( n = nSttPos+2; n < nEndPos && lcl_IsInAsciiArr(
     534           0 :                             sImplSttSkipChars,(cCh = rTxt[ n ]));
     535             :                         ++n )
     536             :                     ;
     537             : 
     538             :                 // found: " --[<AnySttChars>][A-z0-9]
     539           0 :                 if( rCC.isLetterNumeric( OUString(cCh) ) )
     540             :                 {
     541           0 :                     for( n = nSttPos-1; n && lcl_IsInAsciiArr(
     542           0 :                             sImplEndSkipChars,(cCh = rTxt[ --n ])); )
     543             :                         ;
     544             : 
     545             :                     // found: "[A-z0-9][<AnyEndChars>] --[<AnySttChars>][A-z0-9]
     546           0 :                     if( rCC.isLetterNumeric( OUString(cCh) ))
     547             :                     {
     548           0 :                         rDoc.Delete( nSttPos, nSttPos + 2 );
     549           0 :                         rDoc.Insert( nSttPos, bAlwaysUseEmDash ? OUString(cEmDash) : OUString(cEnDash) );
     550           0 :                         bRet = true;
     551             :                     }
     552             :                 }
     553             :             }
     554             :         }
     555           0 :         else if( 3 < nSttPos &&
     556           0 :                  ' ' == rTxt[ nSttPos-1 ] &&
     557           0 :                  '-' == rTxt[ nSttPos-2 ])
     558             :         {
     559           0 :             sal_Int32 n, nLen = 1, nTmpPos = nSttPos - 2;
     560           0 :             if( '-' == ( cCh = rTxt[ nTmpPos-1 ]) )
     561             :             {
     562           0 :                 --nTmpPos;
     563           0 :                 ++nLen;
     564           0 :                 cCh = rTxt[ nTmpPos-1 ];
     565             :             }
     566           0 :             if( ' ' == cCh )
     567             :             {
     568           0 :                 for( n = nSttPos; n < nEndPos && lcl_IsInAsciiArr(
     569           0 :                             sImplSttSkipChars,(cCh = rTxt[ n ]));
     570             :                         ++n )
     571             :                     ;
     572             : 
     573             :                 // found: " - [<AnySttChars>][A-z0-9]
     574           0 :                 if( rCC.isLetterNumeric( OUString(cCh) ) )
     575             :                 {
     576           0 :                     cCh = ' ';
     577           0 :                     for( n = nTmpPos-1; n && lcl_IsInAsciiArr(
     578           0 :                             sImplEndSkipChars,(cCh = rTxt[ --n ])); )
     579             :                             ;
     580             :                     // found: "[A-z0-9][<AnyEndChars>] - [<AnySttChars>][A-z0-9]
     581           0 :                     if( rCC.isLetterNumeric( OUString(cCh) ))
     582             :                     {
     583           0 :                         rDoc.Delete( nTmpPos, nTmpPos + nLen );
     584           0 :                         rDoc.Insert( nTmpPos, bAlwaysUseEmDash ? OUString(cEmDash) : OUString(cEnDash) );
     585           0 :                         bRet = true;
     586             :                     }
     587             :                 }
     588             :             }
     589             :         }
     590             :     }
     591             : 
     592             :     // Replace [A-z0-9]--[A-z0-9] double dash with "emDash" or "enDash"
     593             :     // [0-9]--[0-9] double dash always replaced with "enDash"
     594             :     // Finnish and Hungarian use enDash instead of emDash.
     595           4 :     bool bEnDash = (eLang == LANGUAGE_HUNGARIAN || eLang == LANGUAGE_FINNISH);
     596           4 :     if( ((cEmDash && !bEnDash) || (cEnDash && bEnDash)) && 4 <= nEndPos - nSttPos )
     597             :     {
     598           4 :         OUString sTmp( rTxt.copy( nSttPos, nEndPos - nSttPos ) );
     599           4 :         sal_Int32 nFndPos = sTmp.indexOf("--");
     600           4 :         if( nFndPos != -1 && nFndPos &&
     601           0 :             nFndPos + 2 < sTmp.getLength() &&
     602           0 :             ( rCC.isLetterNumeric( sTmp, nFndPos - 1 ) ||
     603           4 :               lcl_IsInAsciiArr( sImplEndSkipChars, rTxt[ nFndPos - 1 ] )) &&
     604           0 :             ( rCC.isLetterNumeric( sTmp, nFndPos + 2 ) ||
     605           0 :             lcl_IsInAsciiArr( sImplSttSkipChars, rTxt[ nFndPos + 2 ] )))
     606             :         {
     607           0 :             nSttPos = nSttPos + nFndPos;
     608           0 :             rDoc.Delete( nSttPos, nSttPos + 2 );
     609           0 :             rDoc.Insert( nSttPos, (bEnDash || (rCC.isDigit( sTmp, nFndPos - 1 ) &&
     610           0 :                 rCC.isDigit( sTmp, nFndPos + 2 )) ? OUString(cEnDash) : OUString(cEmDash)) );
     611           0 :             bRet = true;
     612           4 :         }
     613             :     }
     614           4 :     return bRet;
     615             : }
     616             : 
     617             : 
     618           0 : bool SvxAutoCorrect::FnAddNonBrkSpace(
     619             :                                 SvxAutoCorrDoc& rDoc, const OUString& rTxt,
     620             :                                 sal_Int32, sal_Int32 nEndPos,
     621             :                                 LanguageType eLang )
     622             : {
     623           0 :     bool bRet = false;
     624             : 
     625           0 :     CharClass& rCC = GetCharClass( eLang );
     626             : 
     627           0 :     if ( rCC.getLanguageTag().getLanguage() == "fr" )
     628             :     {
     629           0 :         bool bFrCA = (rCC.getLanguageTag().getCountry() == "CA");
     630           0 :         OUString allChars = ":;?!%";
     631           0 :         OUString chars( allChars );
     632           0 :         if ( bFrCA )
     633           0 :             chars = ":";
     634             : 
     635           0 :         sal_Unicode cChar = rTxt[ nEndPos ];
     636           0 :         bool bHasSpace = chars.indexOf( cChar ) != -1;
     637           0 :         bool bIsSpecial = allChars.indexOf( cChar ) != -1;
     638           0 :         if ( bIsSpecial )
     639             :         {
     640             :             // Get the last word delimiter position
     641           0 :             sal_Int32 nSttWdPos = nEndPos;
     642           0 :             bool bWasWordDelim = false;
     643           0 :             while( nSttWdPos && !(bWasWordDelim = IsWordDelim( rTxt[ --nSttWdPos ])))
     644             :                 ;
     645             : 
     646             :             //See if the text is the start of a protocol string, e.g. have text of
     647             :             //"http" see if it is the start of "http:" and if so leave it alone
     648           0 :             sal_Int32 nIndex = nSttWdPos + (bWasWordDelim ? 1 : 0);
     649           0 :             sal_Int32 nProtocolLen = nEndPos - nSttWdPos + 1;
     650           0 :             if (nIndex + nProtocolLen <= rTxt.getLength())
     651             :             {
     652           0 :                 if (INetURLObject::CompareProtocolScheme(rTxt.copy(nIndex, nProtocolLen)) != INET_PROT_NOT_VALID)
     653           0 :                     return false;
     654             :             }
     655             : 
     656             :             // Check the presence of "://" in the word
     657           0 :             sal_Int32 nStrPos = rTxt.indexOf( "://", nSttWdPos + 1 );
     658           0 :             if ( nStrPos == -1 && nEndPos > 0 )
     659             :             {
     660             :                 // Check the previous char
     661           0 :                 sal_Unicode cPrevChar = rTxt[ nEndPos - 1 ];
     662           0 :                 if ( ( chars.indexOf( cPrevChar ) == -1 ) && cPrevChar != '\t' )
     663             :                 {
     664             :                     // Remove any previous normal space
     665           0 :                     sal_Int32 nPos = nEndPos - 1;
     666           0 :                     while ( cPrevChar == ' ' || cPrevChar == cNonBreakingSpace )
     667             :                     {
     668           0 :                         if ( nPos == 0 ) break;
     669           0 :                         nPos--;
     670           0 :                         cPrevChar = rTxt[ nPos ];
     671             :                     }
     672             : 
     673           0 :                     nPos++;
     674           0 :                     if ( nEndPos - nPos > 0 )
     675           0 :                         rDoc.Delete( nPos, nEndPos );
     676             : 
     677             :                     // Add the non-breaking space at the end pos
     678           0 :                     if ( bHasSpace )
     679           0 :                         rDoc.Insert( nPos, OUString(cNonBreakingSpace) );
     680           0 :                     bRunNext = true;
     681           0 :                     bRet = true;
     682             :                 }
     683           0 :                 else if ( chars.indexOf( cPrevChar ) != -1 )
     684           0 :                     bRunNext = true;
     685             :             }
     686             :         }
     687           0 :         else if ( cChar == '/' && nEndPos > 1 && rTxt.getLength() > (nEndPos - 1) )
     688             :         {
     689             :             // Remove the hardspace right before to avoid formatting URLs
     690           0 :             sal_Unicode cPrevChar = rTxt[ nEndPos - 1 ];
     691           0 :             sal_Unicode cMaybeSpaceChar = rTxt[ nEndPos - 2 ];
     692           0 :             if ( cPrevChar == ':' && cMaybeSpaceChar == cNonBreakingSpace )
     693             :             {
     694           0 :                 rDoc.Delete( nEndPos - 2, nEndPos - 1 );
     695           0 :                 bRet = true;
     696             :             }
     697           0 :         }
     698             :     }
     699             : 
     700           0 :     return bRet;
     701             : }
     702             : 
     703             : 
     704           4 : bool SvxAutoCorrect::FnSetINetAttr( SvxAutoCorrDoc& rDoc, const OUString& rTxt,
     705             :                                     sal_Int32 nSttPos, sal_Int32 nEndPos,
     706             :                                     LanguageType eLang )
     707             : {
     708             :     OUString sURL( URIHelper::FindFirstURLInText( rTxt, nSttPos, nEndPos,
     709           4 :                                                 GetCharClass( eLang ) ));
     710           4 :     bool bRet = !sURL.isEmpty();
     711           4 :     if( bRet )          // also Attribut setzen:
     712           0 :         rDoc.SetINetAttr( nSttPos, nEndPos, sURL );
     713           4 :     return bRet;
     714             : }
     715             : 
     716             : 
     717           2 : bool SvxAutoCorrect::FnChgWeightUnderl( SvxAutoCorrDoc& rDoc, const OUString& rTxt,
     718             :                                         sal_Int32 , sal_Int32 nEndPos,
     719             :                                         LanguageType eLang )
     720             : {
     721             :     // Condition:
     722             :     //  at the beginning:   _ or * after Space with the folloeing !Space
     723             :     //  at the end:         _ or * before Space (word delimiter?)
     724             : 
     725           2 :     sal_Unicode c, cInsChar = rTxt[ nEndPos ];  // underline or bold
     726           2 :     if( ++nEndPos != rTxt.getLength() &&
     727           0 :         !IsWordDelim( rTxt[ nEndPos ] ) )
     728           0 :         return false;
     729             : 
     730           2 :     --nEndPos;
     731             : 
     732           2 :     bool bAlphaNum = false;
     733           2 :     sal_Int32 nPos = nEndPos;
     734           2 :     sal_Int32  nFndPos = -1;
     735           2 :     CharClass& rCC = GetCharClass( eLang );
     736             : 
     737          12 :     while( nPos )
     738             :     {
     739           8 :         switch( c = rTxt[ --nPos ] )
     740             :         {
     741             :         case '_':
     742             :         case '*':
     743           2 :             if( c == cInsChar )
     744             :             {
     745           4 :                 if( bAlphaNum && nPos+1 < nEndPos && ( !nPos ||
     746           4 :                     IsWordDelim( rTxt[ nPos-1 ])) &&
     747           2 :                     !IsWordDelim( rTxt[ nPos+1 ]))
     748           2 :                         nFndPos = nPos;
     749             :                 else
     750             :                     // Condition is not satisfied, so cancel
     751           0 :                     nFndPos = -1;
     752           2 :                 nPos = 0;
     753             :             }
     754           2 :             break;
     755             :         default:
     756           6 :             if( !bAlphaNum )
     757           2 :                 bAlphaNum = rCC.isLetterNumeric( rTxt, nPos );
     758             :         }
     759             :     }
     760             : 
     761           2 :     if( -1 != nFndPos )
     762             :     {
     763             :         // first delete the Character at the end - this allows insertion
     764             :         // of an empty hint in SetAttr which would be removed by Delete
     765             :         // (fdo#62536, AUTOFMT in Writer)
     766           2 :         rDoc.Delete( nEndPos, nEndPos + 1 );
     767           2 :         rDoc.Delete( nFndPos, nFndPos + 1 );
     768             :         // Span the Attribute over the area
     769             :         // the end.
     770           2 :         if( '*' == cInsChar )           // Bold
     771             :         {
     772           2 :             SvxWeightItem aSvxWeightItem( WEIGHT_BOLD, SID_ATTR_CHAR_WEIGHT );
     773             :             rDoc.SetAttr( nFndPos, nEndPos - 1,
     774             :                             SID_ATTR_CHAR_WEIGHT,
     775           2 :                             aSvxWeightItem);
     776             :         }
     777             :         else                            // underline
     778             :         {
     779           0 :             SvxUnderlineItem aSvxUnderlineItem( UNDERLINE_SINGLE, SID_ATTR_CHAR_UNDERLINE );
     780             :             rDoc.SetAttr( nFndPos, nEndPos - 1,
     781             :                             SID_ATTR_CHAR_UNDERLINE,
     782           0 :                             aSvxUnderlineItem);
     783             :         }
     784             :     }
     785             : 
     786           2 :     return -1 != nFndPos;
     787             : }
     788             : 
     789             : 
     790           4 : bool SvxAutoCorrect::FnCptlSttSntnc( SvxAutoCorrDoc& rDoc,
     791             :                                     const OUString& rTxt, bool bNormalPos,
     792             :                                     sal_Int32 nSttPos, sal_Int32 nEndPos,
     793             :                                     LanguageType eLang )
     794             : {
     795             : 
     796           4 :     if( rTxt.isEmpty() || nEndPos <= nSttPos )
     797           0 :         return false;
     798             : 
     799           4 :     CharClass& rCC = GetCharClass( eLang );
     800           4 :     OUString aText( rTxt );
     801           4 :     const sal_Unicode *pStart = aText.getStr(),
     802           4 :                       *pStr = pStart + nEndPos,
     803           4 :                       *pWordStt = 0,
     804           4 :                       *pDelim = 0;
     805             : 
     806           4 :     bool bAtStart = false;
     807          24 :     do {
     808          26 :         --pStr;
     809          26 :         if (rCC.isLetter(aText, pStr - pStart))
     810             :         {
     811          22 :             if( !pWordStt )
     812           4 :                 pDelim = pStr+1;
     813          22 :             pWordStt = pStr;
     814             :         }
     815           4 :         else if (pWordStt && !rCC.isDigit(aText, pStr - pStart))
     816             :         {
     817          10 :             if( lcl_IsInAsciiArr( sImplWordChars, *pStr ) &&
     818           4 :                 pWordStt - 1 == pStr &&
     819             :                 // Installation at beginning of paragraph. Replaced < by <= (#i38971#)
     820           8 :                 (pStart + 1) <= pStr &&
     821           2 :                 rCC.isLetter(aText, pStr-1 - pStart))
     822           2 :                 pWordStt = --pStr;
     823             :             else
     824           2 :                 break;
     825             :         }
     826             :     } while( ! ( bAtStart = (pStart == pStr) ) );
     827             : 
     828           4 :     if (!pWordStt)
     829           0 :         return false;    // no character to be replaced
     830             : 
     831             : 
     832           4 :     if (rCC.isDigit(aText, pStr - pStart))
     833           0 :         return false; // already ok
     834             : 
     835           4 :     if (IsUpperLetter(rCC.getCharacterType(aText, pWordStt - pStart)))
     836           4 :         return false; // already ok
     837             : 
     838             :     //See if the text is the start of a protocol string, e.g. have text of
     839             :     //"http" see if it is the start of "http:" and if so leave it alone
     840           0 :     sal_Int32 nIndex = pWordStt - pStart;
     841           0 :     sal_Int32 nProtocolLen = pDelim - pWordStt + 1;
     842           0 :     if (nIndex + nProtocolLen <= rTxt.getLength())
     843             :     {
     844           0 :         if (INetURLObject::CompareProtocolScheme(rTxt.copy(nIndex, nProtocolLen)) != INET_PROT_NOT_VALID)
     845           0 :             return false; // already ok
     846             :     }
     847             : 
     848           0 :     if (0x1 == *pWordStt || 0x2 == *pWordStt)
     849           0 :         return false; // already ok
     850             : 
     851           0 :     if( *pDelim && 2 >= pDelim - pWordStt &&
     852           0 :         lcl_IsInAsciiArr( ".-)>", *pDelim ) )
     853           0 :         return false;
     854             : 
     855           0 :     if( !bAtStart ) // Still no beginning of a paragraph?
     856             :     {
     857           0 :         if ( IsWordDelim( *pStr ) )
     858             :         {
     859           0 :             while( ! ( bAtStart = (pStart == pStr--) ) && IsWordDelim( *pStr ) )
     860             :                 ;
     861             :         }
     862             :         // Asian full stop, full width full stop, full width exclamation mark
     863             :         // and full width question marks are treated as word delimiters
     864           0 :         else if ( 0x3002 != *pStr && 0xFF0E != *pStr && 0xFF01 != *pStr &&
     865           0 :                   0xFF1F != *pStr )
     866           0 :             return false; // no valid separator -> no replacement
     867             :     }
     868             : 
     869           0 :     if( bAtStart )  // at the beginning of a paragraph?
     870             :     {
     871             :         // Check out the previous paragraph, if it exists.
     872             :         // If so, then check to paragraph separator at the end.
     873           0 :         OUString const*const pPrevPara = rDoc.GetPrevPara(bNormalPos);
     874           0 :         if (!pPrevPara)
     875             :         {
     876             :             // valid separator -> replace
     877           0 :             OUString sChar( *pWordStt );
     878           0 :             sChar = rCC.titlecase(sChar); //see fdo#56740
     879           0 :             return  !comphelper::string::equals(sChar, *pWordStt) &&
     880           0 :                     rDoc.ReplaceRange( pWordStt - pStart, 1, sChar );
     881             :         }
     882             : 
     883           0 :         aText = *pPrevPara;
     884           0 :         bAtStart = false;
     885           0 :         pStart = aText.getStr();
     886           0 :         pStr = pStart + aText.getLength();
     887             : 
     888           0 :         do {            // overwrite all blanks
     889           0 :             --pStr;
     890           0 :             if( !IsWordDelim( *pStr ))
     891           0 :                 break;
     892             :         } while( ! ( bAtStart = (pStart == pStr) ) );
     893             : 
     894           0 :         if( bAtStart )
     895           0 :             return false;  // no valid separator -> no replacement
     896             :     }
     897             : 
     898             :     // Found [ \t]+[A-Z0-9]+ until here. Test now on the paragraph separator.
     899             :     // all three can happen, but not more than once!
     900           0 :     const sal_Unicode* pExceptStt = 0;
     901           0 :     if( !bAtStart )
     902             :     {
     903           0 :         bool bContinue = true;
     904           0 :         int nFlag = C_NONE;
     905           0 :         do {
     906           0 :             switch( *pStr )
     907             :             {
     908             :             // Western and Asian full stop
     909             :             case '.':
     910             :             case 0x3002 :
     911             :             case 0xFF0E :
     912             :                 {
     913           0 :                     if (pStr >= pStart + 2 && *(pStr-2) == '.')
     914             :                     {
     915             :                         //e.g. text "f.o.o. word": Now currently considering
     916             :                         //capitalizing word but second last character of
     917             :                         //previous word is a .  So probably last word is an
     918             :                         //anagram that ends in . and not truly the end of a
     919             :                         //previous sentence, so don't autocapitalize this word
     920           0 :                         return false;
     921             :                     }
     922           0 :                     if( nFlag & C_FULL_STOP )
     923           0 :                         return false;  // no valid separator -> no replacement
     924           0 :                     nFlag |= C_FULL_STOP;
     925           0 :                     pExceptStt = pStr;
     926             :                 }
     927           0 :                 break;
     928             :             case '!':
     929             :             case 0xFF01 :
     930             :                 {
     931           0 :                     if( nFlag & C_EXCLAMATION_MARK )
     932           0 :                         return false;   // no valid separator -> no replacement
     933           0 :                     nFlag |= C_EXCLAMATION_MARK;
     934             :                 }
     935           0 :                 break;
     936             :             case '?':
     937             :             case 0xFF1F :
     938             :                 {
     939           0 :                     if( nFlag & C_QUESTION_MARK)
     940           0 :                         return false;   // no valid separator -> no replacement
     941           0 :                     nFlag |= C_QUESTION_MARK;
     942             :                 }
     943           0 :                 break;
     944             :             default:
     945           0 :                 if( !nFlag )
     946           0 :                     return false;       // no valid separator -> no replacement
     947             :                 else
     948           0 :                     bContinue = false;
     949           0 :                 break;
     950             :             }
     951             : 
     952           0 :             if( bContinue && pStr-- == pStart )
     953             :             {
     954           0 :                 return false;       // no valid separator -> no replacement
     955             :             }
     956             :         } while( bContinue );
     957           0 :         if( C_FULL_STOP != nFlag )
     958           0 :             pExceptStt = 0;
     959             :     }
     960             : 
     961           0 :     if( 2 > ( pStr - pStart ) )
     962           0 :         return false;
     963             : 
     964           0 :     if (!rCC.isLetterNumeric(aText, pStr-- - pStart))
     965             :     {
     966           0 :         bool bValid = false, bAlphaFnd = false;
     967           0 :         const sal_Unicode* pTmpStr = pStr;
     968           0 :         while( !bValid )
     969             :         {
     970           0 :             if( rCC.isDigit( aText, pTmpStr - pStart ) )
     971             :             {
     972           0 :                 bValid = true;
     973           0 :                 pStr = pTmpStr - 1;
     974             :             }
     975           0 :             else if( rCC.isLetter( aText, pTmpStr - pStart ) )
     976             :             {
     977           0 :                 if( bAlphaFnd )
     978             :                 {
     979           0 :                     bValid = true;
     980           0 :                     pStr = pTmpStr;
     981             :                 }
     982             :                 else
     983           0 :                     bAlphaFnd = true;
     984             :             }
     985           0 :             else if( bAlphaFnd || IsWordDelim( *pTmpStr ) )
     986           0 :                 break;
     987             : 
     988           0 :             if( pTmpStr == pStart )
     989           0 :                 break;
     990             : 
     991           0 :             --pTmpStr;
     992             :         }
     993             : 
     994           0 :         if( !bValid )
     995           0 :             return false;       // no valid separator -> no replacement
     996             :     }
     997             : 
     998           0 :     bool bNumericOnly = '0' <= *(pStr+1) && *(pStr+1) <= '9';
     999             : 
    1000             :     // Search for the beginning of the word
    1001           0 :     while( !IsWordDelim( *pStr ))
    1002             :     {
    1003           0 :         if( bNumericOnly && rCC.isLetter( aText, pStr - pStart ) )
    1004           0 :             bNumericOnly = false;
    1005             : 
    1006           0 :         if( pStart == pStr )
    1007           0 :             break;
    1008             : 
    1009           0 :         --pStr;
    1010             :     }
    1011             : 
    1012           0 :     if( bNumericOnly )      // consists of only numbers, then not
    1013           0 :         return false;
    1014             : 
    1015           0 :     if( IsWordDelim( *pStr ))
    1016           0 :         ++pStr;
    1017             : 
    1018           0 :     OUString sWord;
    1019             : 
    1020             :     // check on the basis of the exception list
    1021           0 :     if( pExceptStt )
    1022             :     {
    1023           0 :         sWord = OUString(pStr, pExceptStt - pStr + 1);
    1024           0 :         if( FindInCplSttExceptList(eLang, sWord) )
    1025           0 :             return false;
    1026             : 
    1027             :         // Delete all non alphanumeric. Test the characters at the
    1028             :         // beginning/end of the word ( recognizes: "(min.", "/min.", and so on.)
    1029           0 :         OUString sTmp( sWord );
    1030           0 :         while( !sTmp.isEmpty() &&
    1031           0 :                 !rCC.isLetterNumeric( sTmp, 0 ) )
    1032           0 :             sTmp = sTmp.copy(1);
    1033             : 
    1034             :         // Remove all non alphanumeric characters towards the end up until
    1035             :         // the last one.
    1036           0 :         sal_Int32 nLen = sTmp.getLength();
    1037           0 :         while( nLen && !rCC.isLetterNumeric( sTmp, nLen-1 ) )
    1038           0 :             --nLen;
    1039           0 :         if( nLen + 1 < sTmp.getLength() )
    1040           0 :             sTmp = sTmp.copy( 0, nLen + 1 );
    1041             : 
    1042           0 :         if( !sTmp.isEmpty() && sTmp.getLength() != sWord.getLength() &&
    1043           0 :             FindInCplSttExceptList(eLang, sTmp))
    1044           0 :             return false;
    1045             : 
    1046           0 :         if(FindInCplSttExceptList(eLang, sWord, true))
    1047           0 :             return false;
    1048             :     }
    1049             : 
    1050             :     // Ok, then replace
    1051           0 :     sal_Unicode cSave = *pWordStt;
    1052           0 :     nSttPos = pWordStt - rTxt.getStr();
    1053           0 :     OUString sChar( cSave );
    1054           0 :     sChar = rCC.titlecase(sChar); //see fdo#56740
    1055           0 :     bool bRet = sChar[0] != cSave && rDoc.ReplaceRange( nSttPos, 1, sChar );
    1056             : 
    1057             :     // Parahaps someone wants to have the word
    1058           0 :     if( bRet && SaveWordCplSttLst & nFlags )
    1059           0 :         rDoc.SaveCpltSttWord( CptlSttSntnc, nSttPos, sWord, cSave );
    1060             : 
    1061           0 :     return bRet;
    1062             : }
    1063             : 
    1064           0 : bool SvxAutoCorrect::FnCorrectCapsLock( SvxAutoCorrDoc& rDoc, const OUString& rTxt,
    1065             :                                         sal_Int32 nSttPos, sal_Int32 nEndPos,
    1066             :                                         LanguageType eLang )
    1067             : {
    1068           0 :     if (nEndPos - nSttPos < 2)
    1069             :         // string must be at least 2-character long.
    1070           0 :         return false;
    1071             : 
    1072           0 :     CharClass& rCC = GetCharClass( eLang );
    1073             : 
    1074             :     // Check the first 2 letters.
    1075           0 :     if ( !IsLowerLetter(rCC.getCharacterType(rTxt, nSttPos)) )
    1076           0 :         return false;
    1077             : 
    1078           0 :     if ( !IsUpperLetter(rCC.getCharacterType(rTxt, nSttPos+1)) )
    1079           0 :         return false;
    1080             : 
    1081           0 :     OUString aConverted;
    1082           0 :     aConverted += rCC.uppercase(OUString(rTxt[nSttPos]));
    1083           0 :     aConverted += rCC.lowercase(OUString(rTxt[nSttPos+1]));
    1084             : 
    1085           0 :     for( sal_Int32 i = nSttPos+2; i < nEndPos; ++i )
    1086             :     {
    1087           0 :         if ( IsLowerLetter(rCC.getCharacterType(rTxt, i)) )
    1088             :             // A lowercase letter disqualifies the whole text.
    1089           0 :             return false;
    1090             : 
    1091           0 :         if ( IsUpperLetter(rCC.getCharacterType(rTxt, i)) )
    1092             :             // Another uppercase letter.  Convert it.
    1093           0 :             aConverted += rCC.lowercase(OUString(rTxt[i]));
    1094             :         else
    1095             :             // This is not an alphabetic letter.  Leave it as-is.
    1096           0 :             aConverted += OUString( rTxt[i] );
    1097             :     }
    1098             : 
    1099             :     // Replace the word.
    1100           0 :     rDoc.Delete(nSttPos, nEndPos);
    1101           0 :     rDoc.Insert(nSttPos, aConverted);
    1102             : 
    1103           0 :     return true;
    1104             : }
    1105             : 
    1106             : 
    1107           0 : sal_Unicode SvxAutoCorrect::GetQuote( sal_Unicode cInsChar, bool bSttQuote,
    1108             :                                         LanguageType eLang ) const
    1109             : {
    1110             :     sal_Unicode cRet = bSttQuote ? ( '\"' == cInsChar
    1111             :                                     ? GetStartDoubleQuote()
    1112             :                                     : GetStartSingleQuote() )
    1113             :                                    : ( '\"' == cInsChar
    1114             :                                     ? GetEndDoubleQuote()
    1115           0 :                                     : GetEndSingleQuote() );
    1116           0 :     if( !cRet )
    1117             :     {
    1118             :         // then through the Language find the right character
    1119           0 :         if( LANGUAGE_NONE == eLang )
    1120           0 :             cRet = cInsChar;
    1121             :         else
    1122             :         {
    1123           0 :             LocaleDataWrapper& rLcl = GetLocaleDataWrapper( eLang );
    1124             :             OUString sRet( bSttQuote
    1125             :                             ? ( '\"' == cInsChar
    1126             :                                 ? rLcl.getDoubleQuotationMarkStart()
    1127             :                                 : rLcl.getQuotationMarkStart() )
    1128             :                             : ( '\"' == cInsChar
    1129             :                                 ? rLcl.getDoubleQuotationMarkEnd()
    1130           0 :                                 : rLcl.getQuotationMarkEnd() ));
    1131           0 :             cRet = !sRet.isEmpty() ? sRet[0] : cInsChar;
    1132             :         }
    1133             :     }
    1134           0 :     return cRet;
    1135             : }
    1136             : 
    1137           0 : void SvxAutoCorrect::InsertQuote( SvxAutoCorrDoc& rDoc, sal_Int32 nInsPos,
    1138             :                                     sal_Unicode cInsChar, bool bSttQuote,
    1139             :                                     bool bIns )
    1140             : {
    1141           0 :     LanguageType eLang = rDoc.GetLanguage( nInsPos, false );
    1142           0 :     sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang );
    1143             : 
    1144           0 :     OUString sChg( cInsChar );
    1145           0 :     if( bIns )
    1146           0 :         rDoc.Insert( nInsPos, sChg );
    1147             :     else
    1148           0 :         rDoc.Replace( nInsPos, sChg );
    1149             : 
    1150           0 :     sChg = OUString(cRet);
    1151             : 
    1152           0 :     if( '\"' == cInsChar )
    1153             :     {
    1154           0 :         if( LANGUAGE_SYSTEM == eLang )
    1155           0 :             eLang = GetAppLang().getLanguageType();
    1156           0 :         switch( eLang )
    1157             :         {
    1158             :         case LANGUAGE_FRENCH:
    1159             :         case LANGUAGE_FRENCH_BELGIAN:
    1160             :         case LANGUAGE_FRENCH_CANADIAN:
    1161             :         case LANGUAGE_FRENCH_SWISS:
    1162             :         case LANGUAGE_FRENCH_LUXEMBOURG:
    1163             :             {
    1164           0 :                 OUString s( cNonBreakingSpace );
    1165             :                     // UNICODE code for no break space
    1166           0 :                 if( rDoc.Insert( bSttQuote ? nInsPos+1 : nInsPos, s ))
    1167             :                 {
    1168           0 :                     if( !bSttQuote )
    1169           0 :                         ++nInsPos;
    1170           0 :                 }
    1171             :             }
    1172           0 :             break;
    1173             :         }
    1174             :     }
    1175             : 
    1176           0 :     rDoc.Replace( nInsPos, sChg );
    1177           0 : }
    1178             : 
    1179           0 : OUString SvxAutoCorrect::GetQuote( SvxAutoCorrDoc& rDoc, sal_Int32 nInsPos,
    1180             :                                 sal_Unicode cInsChar, bool bSttQuote )
    1181             : {
    1182           0 :     LanguageType eLang = rDoc.GetLanguage( nInsPos, false );
    1183           0 :     sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang );
    1184             : 
    1185           0 :     OUString sRet = OUString(cRet);
    1186             : 
    1187           0 :     if( '\"' == cInsChar )
    1188             :     {
    1189           0 :         if( LANGUAGE_SYSTEM == eLang )
    1190           0 :             eLang = GetAppLang().getLanguageType();
    1191           0 :         switch( eLang )
    1192             :         {
    1193             :         case LANGUAGE_FRENCH:
    1194             :         case LANGUAGE_FRENCH_BELGIAN:
    1195             :         case LANGUAGE_FRENCH_CANADIAN:
    1196             :         case LANGUAGE_FRENCH_SWISS:
    1197             :         case LANGUAGE_FRENCH_LUXEMBOURG:
    1198           0 :             if( bSttQuote )
    1199           0 :                 sRet += " ";
    1200             :             else
    1201           0 :                 sRet = " " + sRet;
    1202           0 :             break;
    1203             :         }
    1204             :     }
    1205           0 :     return sRet;
    1206             : }
    1207             : 
    1208             : sal_uLong
    1209           6 : SvxAutoCorrect::DoAutoCorrect( SvxAutoCorrDoc& rDoc, const OUString& rTxt,
    1210             :                                     sal_Int32 nInsPos, sal_Unicode cChar,
    1211             :                                     bool bInsert, vcl::Window* pFrameWin )
    1212             : {
    1213           6 :     sal_uLong nRet = 0;
    1214           6 :     bool bIsNextRun = bRunNext;
    1215           6 :     bRunNext = false;  // if it was set, then it has to be turned off
    1216             : 
    1217             :     do{                                 // only for middle check loop !!
    1218           6 :         if( cChar )
    1219             :         {
    1220             :             // Prevent double space
    1221          16 :             if( nInsPos && ' ' == cChar &&
    1222          10 :                 IsAutoCorrFlag( IgnoreDoubleSpace ) &&
    1223           0 :                 ' ' == rTxt[ nInsPos - 1 ])
    1224             :             {
    1225           0 :                 nRet = IgnoreDoubleSpace;
    1226           2 :                 break;
    1227             :             }
    1228             : 
    1229           6 :             bool bSingle = '\'' == cChar;
    1230             :             bool bIsReplaceQuote =
    1231          12 :                         (IsAutoCorrFlag( ChgQuotes ) && ('\"' == cChar )) ||
    1232          12 :                         (IsAutoCorrFlag( ChgSglQuotes ) && bSingle );
    1233           6 :             if( bIsReplaceQuote )
    1234             :             {
    1235             :                 sal_Unicode cPrev;
    1236           0 :                 bool bSttQuote = !nInsPos ||
    1237           0 :                         IsWordDelim( ( cPrev = rTxt[ nInsPos-1 ])) ||
    1238           0 :                         lcl_IsInAsciiArr( "([{", cPrev ) ||
    1239           0 :                         ( cEmDash && cEmDash == cPrev ) ||
    1240           0 :                         ( cEnDash && cEnDash == cPrev );
    1241             : 
    1242           0 :                 InsertQuote( rDoc, nInsPos, cChar, bSttQuote, bInsert );
    1243           0 :                 nRet = bSingle ? ChgSglQuotes : ChgQuotes;
    1244           0 :                 break;
    1245             :             }
    1246             : 
    1247           6 :             if( bInsert )
    1248           6 :                 rDoc.Insert( nInsPos, OUString(cChar) );
    1249             :             else
    1250           0 :                 rDoc.Replace( nInsPos, OUString(cChar) );
    1251             : 
    1252             :             // Hardspaces autocorrection
    1253           6 :             if ( IsAutoCorrFlag( AddNonBrkSpace ) )
    1254             :             {
    1255           6 :                 if ( NeedsHardspaceAutocorr( cChar ) &&
    1256           0 :                     FnAddNonBrkSpace( rDoc, rTxt, 0, nInsPos, rDoc.GetLanguage( nInsPos, false ) ) )
    1257             :                 {
    1258           0 :                     nRet = AddNonBrkSpace;
    1259             :                 }
    1260           6 :                 else if ( bIsNextRun && !IsAutoCorrectChar( cChar ) )
    1261             :                 {
    1262             :                     // Remove the NBSP if it wasn't an autocorrection
    1263           0 :                     if ( nInsPos != 0 && NeedsHardspaceAutocorr( rTxt[ nInsPos - 1 ] ) &&
    1264           0 :                             cChar != ' ' && cChar != '\t' && cChar != cNonBreakingSpace )
    1265             :                     {
    1266             :                         // Look for the last HARD_SPACE
    1267           0 :                         sal_Int32 nPos = nInsPos - 1;
    1268           0 :                         bool bContinue = true;
    1269           0 :                         while ( bContinue )
    1270             :                         {
    1271           0 :                             const sal_Unicode cTmpChar = rTxt[ nPos ];
    1272           0 :                             if ( cTmpChar == cNonBreakingSpace )
    1273             :                             {
    1274           0 :                                 rDoc.Delete( nPos, nPos + 1 );
    1275           0 :                                 nRet = AddNonBrkSpace;
    1276           0 :                                 bContinue = false;
    1277             :                             }
    1278           0 :                             else if ( !NeedsHardspaceAutocorr( cTmpChar ) || nPos == 0 )
    1279           0 :                                 bContinue = false;
    1280           0 :                             nPos--;
    1281             :                         }
    1282             :                     }
    1283             :                 }
    1284             :             }
    1285             :         }
    1286             : 
    1287           6 :         if( !nInsPos )
    1288           0 :             break;
    1289             : 
    1290           6 :         sal_Int32 nPos = nInsPos - 1;
    1291             : 
    1292           6 :         if( IsWordDelim( rTxt[ nPos ]))
    1293           0 :             break;
    1294             : 
    1295             :         // Set bold or underline automatically?
    1296           6 :         if (('*' == cChar || '_' == cChar) && (nPos+1 < rTxt.getLength()))
    1297             :         {
    1298           4 :             if( IsAutoCorrFlag( ChgWeightUnderl ) &&
    1299           2 :                 FnChgWeightUnderl( rDoc, rTxt, 0, nPos+1 ) )
    1300           2 :                 nRet = ChgWeightUnderl;
    1301           2 :             break;
    1302             :         }
    1303             : 
    1304           4 :         while( nPos && !IsWordDelim( rTxt[ --nPos ]))
    1305             :             ;
    1306             : 
    1307             :         // Found a Paragraph-start or a Blank, search for the word shortcut in
    1308             :         // auto.
    1309           4 :         sal_Int32 nCapLttrPos = nPos+1;        // on the 1st Character
    1310           4 :         if( !nPos && !IsWordDelim( rTxt[ 0 ]))
    1311           4 :             --nCapLttrPos;          // Absatz Anfang und kein Blank !
    1312             : 
    1313           4 :         LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, false );
    1314           4 :         if( LANGUAGE_SYSTEM == eLang )
    1315           4 :             eLang = MsLangId::getSystemLanguage();
    1316           4 :         CharClass& rCC = GetCharClass( eLang );
    1317             : 
    1318             :         // no symbol characters
    1319           4 :         if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nInsPos ))
    1320           0 :             break;
    1321             : 
    1322           4 :         if( IsAutoCorrFlag( Autocorrect ) )
    1323             :         {
    1324           4 :             OUString aPara;
    1325           4 :             OUString* pPara = IsAutoCorrFlag(CptlSttSntnc) ? &aPara : 0;
    1326             : 
    1327             :             // since LibO 4.1, '-' is a word separator
    1328             :             // fdo#67742 avoid "--" to be replaced by "–" if next is "-"
    1329           4 :             if( rTxt.endsWith( "---" ) )
    1330           0 :                     break;
    1331             :             bool bChgWord = rDoc.ChgAutoCorrWord( nCapLttrPos, nInsPos,
    1332           4 :                                                     *this, pPara );
    1333           4 :             if( !bChgWord )
    1334             :             {
    1335           4 :                 sal_Int32 nCapLttrPos1 = nCapLttrPos, nInsPos1 = nInsPos;
    1336          12 :                 while( nCapLttrPos1 < nInsPos &&
    1337           4 :                         lcl_IsInAsciiArr( sImplSttSkipChars, rTxt[ nCapLttrPos1 ] )
    1338             :                         )
    1339           0 :                         ++nCapLttrPos1;
    1340          12 :                 while( nCapLttrPos1 < nInsPos1 && nInsPos1 &&
    1341           4 :                         lcl_IsInAsciiArr( sImplEndSkipChars, rTxt[ nInsPos1-1 ] )
    1342             :                         )
    1343           0 :                         --nInsPos1;
    1344             : 
    1345          12 :                 if( (nCapLttrPos1 != nCapLttrPos || nInsPos1 != nInsPos ) &&
    1346           4 :                     nCapLttrPos1 < nInsPos1 &&
    1347           0 :                     rDoc.ChgAutoCorrWord( nCapLttrPos1, nInsPos1, *this, pPara ))
    1348             :                 {
    1349           0 :                     bChgWord = true;
    1350           0 :                     nCapLttrPos = nCapLttrPos1;
    1351             :                 }
    1352             :             }
    1353             : 
    1354           4 :             if( bChgWord )
    1355             :             {
    1356           0 :                 nRet = Autocorrect;
    1357           0 :                 if( !aPara.isEmpty() )
    1358             :                 {
    1359           0 :                     sal_Int32 nEnd = nCapLttrPos;
    1360           0 :                     while( nEnd < aPara.getLength() &&
    1361           0 :                             !IsWordDelim( aPara[ nEnd ]))
    1362           0 :                         ++nEnd;
    1363             : 
    1364             :                     // Capital letter at beginning of paragraph?
    1365           0 :                     if( IsAutoCorrFlag( CptlSttSntnc ) &&
    1366             :                         FnCptlSttSntnc( rDoc, aPara, false,
    1367           0 :                                                 nCapLttrPos, nEnd, eLang ) )
    1368           0 :                         nRet |= CptlSttSntnc;
    1369             : 
    1370           0 :                     if( IsAutoCorrFlag( ChgToEnEmDash ) &&
    1371           0 :                         FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nEnd, eLang ) )
    1372           0 :                         nRet |= ChgToEnEmDash;
    1373             :                 }
    1374           0 :                 break;
    1375           4 :             }
    1376             :         }
    1377             : 
    1378          12 :         if( ( IsAutoCorrFlag( nRet = ChgOrdinalNumber ) &&
    1379           4 :                 (nInsPos >= 2 ) &&       // fdo#69762 avoid autocorrect for 2e-3
    1380           4 :                 ( '-' != cChar || 'E' != toupper(rTxt[nInsPos-1]) || '0' > rTxt[nInsPos-2] || '9' < rTxt[nInsPos-2] ) &&
    1381          12 :                 FnChgOrdinalNumber( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) ||
    1382           8 :             ( IsAutoCorrFlag( nRet = SetINetAttr ) &&
    1383           4 :                 ( ' ' == cChar || '\t' == cChar || 0x0a == cChar || !cChar ) &&
    1384           4 :                 FnSetINetAttr( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) )
    1385             :             ;
    1386             :         else
    1387             :         {
    1388           4 :             bool bLockKeyOn = pFrameWin && (pFrameWin->GetIndicatorState() & INDICATOR_CAPSLOCK);
    1389           4 :             bool bUnsupported = lcl_IsUnsupportedUnicodeChar( rCC, rTxt, nCapLttrPos, nInsPos );
    1390             : 
    1391           4 :             nRet = 0;
    1392           4 :             if ( bLockKeyOn && IsAutoCorrFlag( CorrectCapsLock ) &&
    1393           0 :                  FnCorrectCapsLock( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
    1394             :             {
    1395             :                 // Correct accidental use of cAPS LOCK key (do this only when
    1396             :                 // the caps or shift lock key is pressed).  Turn off the caps
    1397             :                 // lock afterwords.
    1398           0 :                 nRet |= CorrectCapsLock;
    1399           0 :                 pFrameWin->SimulateKeyPress( KEY_CAPSLOCK );
    1400             :             }
    1401             : 
    1402             :             // Capital letter at beginning of paragraph ?
    1403          12 :             if( !bUnsupported &&
    1404           8 :                 IsAutoCorrFlag( CptlSttSntnc ) &&
    1405           4 :                 FnCptlSttSntnc( rDoc, rTxt, true, nCapLttrPos, nInsPos, eLang ) )
    1406           0 :                 nRet |= CptlSttSntnc;
    1407             : 
    1408             :             // Two capital letters at beginning of word ??
    1409          12 :             if( !bUnsupported &&
    1410           8 :                 IsAutoCorrFlag( CptlSttWrd ) &&
    1411           4 :                 FnCptlSttWrd( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
    1412           4 :                 nRet |= CptlSttWrd;
    1413             : 
    1414           8 :             if( IsAutoCorrFlag( ChgToEnEmDash ) &&
    1415           4 :                 FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
    1416           0 :                 nRet |= ChgToEnEmDash;
    1417             :         }
    1418             : 
    1419             :     } while( false );
    1420             : 
    1421           6 :     return nRet;
    1422             : }
    1423             : 
    1424           0 : SvxAutoCorrectLanguageLists& SvxAutoCorrect::_GetLanguageList(
    1425             :                                                         LanguageType eLang )
    1426             : {
    1427           0 :     LanguageTag aLanguageTag( eLang);
    1428           0 :     if (pLangTable->find(aLanguageTag) == pLangTable->end())
    1429           0 :         (void)CreateLanguageFile(aLanguageTag, true);
    1430           0 :     return *(pLangTable->find(aLanguageTag)->second);
    1431             : }
    1432             : 
    1433           0 : void SvxAutoCorrect::SaveCplSttExceptList( LanguageType eLang )
    1434             : {
    1435           0 :     boost::ptr_map<LanguageTag, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(LanguageTag(eLang));
    1436           0 :     if(nTmpVal != pLangTable->end() && nTmpVal->second)
    1437           0 :         nTmpVal->second->SaveCplSttExceptList();
    1438             : #ifdef DBG_UTIL
    1439             :     else
    1440             :     {
    1441             :         SAL_WARN("editeng", "Save an empty list? ");
    1442             :     }
    1443             : #endif
    1444           0 : }
    1445             : 
    1446           0 : void SvxAutoCorrect::SaveWrdSttExceptList(LanguageType eLang)
    1447             : {
    1448           0 :     boost::ptr_map<LanguageTag, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(LanguageTag(eLang));
    1449           0 :     if(nTmpVal != pLangTable->end() && nTmpVal->second)
    1450           0 :         nTmpVal->second->SaveWrdSttExceptList();
    1451             : #ifdef DBG_UTIL
    1452             :     else
    1453             :     {
    1454             :         SAL_WARN("editeng", "Save an empty list? ");
    1455             :     }
    1456             : #endif
    1457           0 : }
    1458             : 
    1459             : // Adds a single word. The list will immediately be written to the file!
    1460           0 : bool SvxAutoCorrect::AddCplSttException( const OUString& rNew,
    1461             :                                         LanguageType eLang )
    1462             : {
    1463           0 :     SvxAutoCorrectLanguageLists* pLists = 0;
    1464             :     // either the right language is present or it will be this in the general list
    1465           0 :     boost::ptr_map<LanguageTag, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(LanguageTag(eLang));
    1466           0 :     if(nTmpVal != pLangTable->end())
    1467           0 :         pLists = nTmpVal->second;
    1468             :     else
    1469             :     {
    1470           0 :         LanguageTag aLangTagUndetermined( LANGUAGE_UNDETERMINED);
    1471           0 :         nTmpVal = pLangTable->find(aLangTagUndetermined);
    1472           0 :         if(nTmpVal != pLangTable->end())
    1473           0 :             pLists = nTmpVal->second;
    1474           0 :         else if(CreateLanguageFile(aLangTagUndetermined, true))
    1475           0 :             pLists = pLangTable->find(aLangTagUndetermined)->second;
    1476             :     }
    1477             :     OSL_ENSURE(pLists, "No auto correction data");
    1478           0 :     return pLists ? pLists->AddToCplSttExceptList(rNew) : false;
    1479             : }
    1480             : 
    1481             : // Adds a single word. The list will immediately be written to the file!
    1482           0 : bool SvxAutoCorrect::AddWrtSttException( const OUString& rNew,
    1483             :                                          LanguageType eLang )
    1484             : {
    1485           0 :     SvxAutoCorrectLanguageLists* pLists = 0;
    1486             :     //either the right language is present or it is set in the general list
    1487           0 :     boost::ptr_map<LanguageTag, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(LanguageTag(eLang));
    1488           0 :     if(nTmpVal != pLangTable->end())
    1489           0 :         pLists = nTmpVal->second;
    1490             :     else
    1491             :     {
    1492           0 :         LanguageTag aLangTagUndetermined( LANGUAGE_UNDETERMINED);
    1493           0 :         nTmpVal = pLangTable->find(aLangTagUndetermined);
    1494           0 :         if(nTmpVal != pLangTable->end())
    1495           0 :             pLists = nTmpVal->second;
    1496           0 :         else if(CreateLanguageFile(aLangTagUndetermined, true))
    1497           0 :             pLists = pLangTable->find(aLangTagUndetermined)->second;
    1498             :     }
    1499             :     OSL_ENSURE(pLists, "No auto correction file!");
    1500           0 :     return pLists ? pLists->AddToWrdSttExceptList(rNew) : false;
    1501             : }
    1502             : 
    1503           0 : bool SvxAutoCorrect::GetPrevAutoCorrWord( SvxAutoCorrDoc& rDoc,
    1504             :                                         const OUString& rTxt, sal_Int32 nPos,
    1505             :                                         OUString& rWord ) const
    1506             : {
    1507           0 :     if( !nPos )
    1508           0 :         return false;
    1509             : 
    1510           0 :     sal_Int32 nEnde = nPos;
    1511             : 
    1512             :     // it must be followed by a blank or tab!
    1513           0 :     if( ( nPos < rTxt.getLength() &&
    1514           0 :         !IsWordDelim( rTxt[ nPos ])) ||
    1515           0 :         IsWordDelim( rTxt[ --nPos ]))
    1516           0 :         return false;
    1517             : 
    1518           0 :     while( nPos && !IsWordDelim( rTxt[ --nPos ]))
    1519             :         ;
    1520             : 
    1521             :     // Found a Paragraph-start or a Blank, search for the word shortcut in
    1522             :     // auto.
    1523           0 :     sal_Int32 nCapLttrPos = nPos+1;        // on the 1st Character
    1524           0 :     if( !nPos && !IsWordDelim( rTxt[ 0 ]))
    1525           0 :         --nCapLttrPos;          // Beginning of pargraph and no Blank!
    1526             : 
    1527           0 :     while( lcl_IsInAsciiArr( sImplSttSkipChars, rTxt[ nCapLttrPos ]) )
    1528           0 :         if( ++nCapLttrPos >= nEnde )
    1529           0 :             return false;
    1530             : 
    1531           0 :     if( 3 > nEnde - nCapLttrPos )
    1532           0 :         return false;
    1533             : 
    1534           0 :     LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, false );
    1535           0 :     if( LANGUAGE_SYSTEM == eLang )
    1536           0 :         eLang = MsLangId::getSystemLanguage();
    1537             : 
    1538           0 :     SvxAutoCorrect* pThis = (SvxAutoCorrect*)this;
    1539           0 :     CharClass& rCC = pThis->GetCharClass( eLang );
    1540             : 
    1541           0 :     if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nEnde ))
    1542           0 :         return false;
    1543             : 
    1544           0 :     rWord = rTxt.copy( nCapLttrPos, nEnde - nCapLttrPos );
    1545           0 :     return true;
    1546             : }
    1547             : 
    1548          36 : bool SvxAutoCorrect::CreateLanguageFile( const LanguageTag& rLanguageTag, bool bNewFile )
    1549             : {
    1550             :     OSL_ENSURE(pLangTable->find(rLanguageTag) == pLangTable->end(), "Language already exists ");
    1551             : 
    1552          36 :     OUString sUserDirFile( GetAutoCorrFileName( rLanguageTag, true, false, false ));
    1553          72 :     OUString sShareDirFile( sUserDirFile );
    1554             : 
    1555          36 :     SvxAutoCorrectLanguageListsPtr pLists = 0;
    1556             : 
    1557          36 :     tools::Time nMinTime( 0, 2 ), nAktTime( tools::Time::SYSTEM ), nLastCheckTime( tools::Time::EMPTY );
    1558             : 
    1559          36 :     std::map<LanguageTag, long>::iterator nFndPos = aLastFileTable.find(rLanguageTag);
    1560         174 :     if(nFndPos != aLastFileTable.end() &&
    1561         168 :        (nLastCheckTime.SetTime(nFndPos->second), nLastCheckTime < nAktTime) &&
    1562          96 :        nAktTime - nLastCheckTime < nMinTime)
    1563             :     {
    1564             :         // no need to test the file, because the last check is not older then
    1565             :         // 2 minutes.
    1566          30 :         if( bNewFile )
    1567             :         {
    1568           0 :             sShareDirFile = sUserDirFile;
    1569           0 :             pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile, sUserDirFile );
    1570           0 :             LanguageTag aTmp(rLanguageTag);     // this insert() needs a non-const reference
    1571           0 :             pLangTable->insert(aTmp, pLists);
    1572           0 :             aLastFileTable.erase(nFndPos);
    1573             :         }
    1574             :     }
    1575          12 :     else if(
    1576          18 :              ( FStatHelper::IsDocument( sUserDirFile ) ||
    1577          24 :                FStatHelper::IsDocument( sShareDirFile =
    1578          18 :                    GetAutoCorrFileName( rLanguageTag, false, false, false ) ) ||
    1579          18 :                FStatHelper::IsDocument( sShareDirFile =
    1580           6 :                    GetAutoCorrFileName( rLanguageTag, false, false, true) )
    1581          18 :              ) ||
    1582             :         ( sShareDirFile = sUserDirFile, bNewFile )
    1583             :           )
    1584             :     {
    1585           0 :         pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile, sUserDirFile );
    1586           0 :         LanguageTag aTmp(rLanguageTag);     // this insert() needs a non-const reference
    1587           0 :         pLangTable->insert(aTmp, pLists);
    1588           0 :         if (nFndPos != aLastFileTable.end())
    1589           0 :             aLastFileTable.erase(nFndPos);
    1590             :     }
    1591           6 :     else if( !bNewFile )
    1592             :     {
    1593           6 :         aLastFileTable[rLanguageTag] = nAktTime.GetTime();
    1594             :     }
    1595          72 :     return pLists != 0;
    1596             : }
    1597             : 
    1598           0 : bool SvxAutoCorrect::PutText( const OUString& rShort, const OUString& rLong,
    1599             :                                 LanguageType eLang )
    1600             : {
    1601           0 :     LanguageTag aLanguageTag( eLang);
    1602           0 :     boost::ptr_map<LanguageTag, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(aLanguageTag);
    1603           0 :     if(nTmpVal != pLangTable->end())
    1604           0 :         return nTmpVal->second->PutText(rShort, rLong);
    1605           0 :     if(CreateLanguageFile(aLanguageTag))
    1606           0 :         return pLangTable->find(aLanguageTag)->second->PutText(rShort, rLong);
    1607           0 :     return false;
    1608             : }
    1609             : 
    1610           0 : bool SvxAutoCorrect::MakeCombinedChanges( std::vector<SvxAutocorrWord>& aNewEntries,
    1611             :                                               std::vector<SvxAutocorrWord>& aDeleteEntries,
    1612             :                                               LanguageType eLang )
    1613             : {
    1614           0 :     LanguageTag aLanguageTag( eLang);
    1615           0 :     boost::ptr_map<LanguageTag, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(aLanguageTag);
    1616           0 :     if(nTmpVal != pLangTable->end())
    1617             :     {
    1618           0 :         return nTmpVal->second->MakeCombinedChanges( aNewEntries, aDeleteEntries );
    1619             :     }
    1620           0 :     else if(CreateLanguageFile( aLanguageTag ))
    1621             :     {
    1622           0 :         return pLangTable->find( aLanguageTag )->second->MakeCombinedChanges( aNewEntries, aDeleteEntries );
    1623             :     }
    1624           0 :     return false;
    1625             : 
    1626             : }
    1627             : 
    1628             : //  - return the replacement text (only for SWG-Format, all other
    1629             : //    can be taken from the word list!)
    1630           0 : bool SvxAutoCorrect::GetLongText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&,
    1631             :                                   const OUString&, OUString& )
    1632             : {
    1633           0 :     return false;
    1634             : }
    1635             : 
    1636             : // Text with attribution (only the SWG - SWG format!)
    1637           0 : bool SvxAutoCorrect::PutText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&,
    1638             :                               const OUString&, const OUString&, SfxObjectShell&, OUString& )
    1639             : {
    1640           0 :     return false;
    1641             : }
    1642             : 
    1643           0 : OUString EncryptBlockName_Imp(const OUString& rName)
    1644             : {
    1645           0 :     OUStringBuffer aName;
    1646           0 :     aName.append('#').append(rName);
    1647           0 :     for (sal_Int32 nLen = rName.getLength(), nPos = 1; nPos < nLen; ++nPos)
    1648             :     {
    1649           0 :         if (lcl_IsInAsciiArr( "!/:.\\", aName[nPos]))
    1650           0 :             aName[nPos] &= 0x0f;
    1651             :     }
    1652           0 :     return aName.makeStringAndClear();
    1653             : }
    1654             : 
    1655             : /* This code is copied from SwXMLTextBlocks::GeneratePackageName */
    1656           0 : static void GeneratePackageName ( const OUString& rShort, OUString& rPackageName )
    1657             : {
    1658           0 :     OString sByte(OUStringToOString(rShort, RTL_TEXTENCODING_UTF7));
    1659           0 :     OUStringBuffer aBuf(OStringToOUString(sByte, RTL_TEXTENCODING_ASCII_US));
    1660             : 
    1661           0 :     for (sal_Int32 nPos = 0; nPos < aBuf.getLength(); ++nPos)
    1662             :     {
    1663           0 :         switch (aBuf[nPos])
    1664             :         {
    1665             :             case '!':
    1666             :             case '/':
    1667             :             case ':':
    1668             :             case '.':
    1669             :             case '\\':
    1670           0 :                 aBuf[nPos] = '_';
    1671           0 :                 break;
    1672             :             default:
    1673           0 :                 break;
    1674             :         }
    1675             :     }
    1676             : 
    1677           0 :     rPackageName = aBuf.makeStringAndClear();
    1678           0 : }
    1679             : 
    1680           0 : static const SvxAutocorrWord* lcl_SearchWordsInList(
    1681             :                 SvxAutoCorrectLanguageListsPtr pList, const OUString& rTxt,
    1682             :                 sal_Int32& rStt, sal_Int32 nEndPos)
    1683             : {
    1684           0 :     const SvxAutocorrWordList* pAutoCorrWordList = pList->GetAutocorrWordList();
    1685           0 :     return pAutoCorrWordList->SearchWordsInList( rTxt, rStt, nEndPos );
    1686             : }
    1687             : 
    1688             : // the search for the words in the substitution table
    1689           4 : const SvxAutocorrWord* SvxAutoCorrect::SearchWordsInList(
    1690             :                 const OUString& rTxt, sal_Int32& rStt, sal_Int32 nEndPos,
    1691             :                 SvxAutoCorrDoc&, LanguageTag& rLang )
    1692             : {
    1693           4 :     const SvxAutocorrWord* pRet = 0;
    1694           4 :     LanguageTag aLanguageTag( rLang);
    1695           4 :     if( aLanguageTag.isSystemLocale() )
    1696           0 :         aLanguageTag.reset( MsLangId::getSystemLanguage());
    1697             : 
    1698             :     /* TODO-BCP47: this is so ugly, should all maybe be a proper fallback
    1699             :      * list instead? */
    1700             : 
    1701             :     // First search for eLang, then US-English -> English
    1702             :     // and last in LANGUAGE_UNDETERMINED
    1703           4 :     if(pLangTable->find(aLanguageTag) != pLangTable->end() || CreateLanguageFile(aLanguageTag, false))
    1704             :     {
    1705             :         //the language is available - so bring it on
    1706           0 :         SvxAutoCorrectLanguageLists* pList = pLangTable->find(aLanguageTag)->second;
    1707           0 :         pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos );
    1708           0 :         if( pRet )
    1709             :         {
    1710           0 :             rLang = aLanguageTag;
    1711           0 :             return pRet;
    1712             :         }
    1713             :     }
    1714             : 
    1715             :     // If it still could not be found here, then keep on searching
    1716             : 
    1717           4 :     LanguageType eLang = aLanguageTag.getLanguageType();
    1718           4 :     LanguageType nTmpKey1 = eLang & 0x7ff, // the main language in many cases DE
    1719           4 :                  nTmpKey2 = eLang & 0x3ff; // otherwise for example EN
    1720           4 :     if(nTmpKey1 != eLang && (pLangTable->find(aLanguageTag.reset(nTmpKey1)) != pLangTable->end() ||
    1721           0 :                 CreateLanguageFile(aLanguageTag, false)))
    1722             :     {
    1723             :         //the language is available - so bring it on
    1724           0 :         SvxAutoCorrectLanguageLists* pList = pLangTable->find(aLanguageTag)->second;
    1725           0 :         pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos );
    1726           0 :         if( pRet )
    1727             :         {
    1728           0 :             rLang = aLanguageTag;
    1729           0 :             return pRet;
    1730             :         }
    1731             :     }
    1732             : 
    1733           8 :     if(nTmpKey2 != eLang && (pLangTable->find(aLanguageTag.reset(nTmpKey2)) != pLangTable->end() ||
    1734           4 :                 CreateLanguageFile(aLanguageTag, false)))
    1735             :     {
    1736             :         //the language is available - so bring it on
    1737           0 :         SvxAutoCorrectLanguageLists* pList = pLangTable->find(aLanguageTag)->second;
    1738           0 :         pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos );
    1739           0 :         if( pRet )
    1740             :         {
    1741           0 :             rLang = aLanguageTag;
    1742           0 :             return pRet;
    1743             :         }
    1744             :     }
    1745             : 
    1746           8 :     if(pLangTable->find(aLanguageTag.reset(LANGUAGE_UNDETERMINED)) != pLangTable->end() ||
    1747           4 :             CreateLanguageFile(aLanguageTag, false))
    1748             :     {
    1749             :         //the language is available - so bring it on
    1750           0 :         SvxAutoCorrectLanguageLists* pList = pLangTable->find(aLanguageTag)->second;
    1751           0 :         pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos );
    1752           0 :         if( pRet )
    1753             :         {
    1754           0 :             rLang = aLanguageTag;
    1755           0 :             return pRet;
    1756             :         }
    1757             :     }
    1758           4 :     return 0;
    1759             : }
    1760             : 
    1761           8 : bool SvxAutoCorrect::FindInWrdSttExceptList( LanguageType eLang,
    1762             :                                              const OUString& sWord )
    1763             : {
    1764           8 :     LanguageTag aLanguageTag( eLang);
    1765             : 
    1766             :     /* TODO-BCP47: again horrible uglyness */
    1767             : 
    1768             :     // First search for eLang, then US-English -> English
    1769             :     // and last in LANGUAGE_UNDETERMINED
    1770           8 :     LanguageType nTmpKey1 = eLang & 0x7ff, // the main language in many cases DE
    1771           8 :                  nTmpKey2 = eLang & 0x3ff; // otherwise for example EN
    1772          16 :     OUString sTemp(sWord);
    1773             : 
    1774           8 :     if(pLangTable->find(aLanguageTag) != pLangTable->end() || CreateLanguageFile(aLanguageTag, false))
    1775             :     {
    1776             :         //the language is available - so bring it on
    1777           0 :         SvxAutoCorrectLanguageLists* pList = pLangTable->find(aLanguageTag)->second;
    1778           0 :         OUString _sTemp(sWord);
    1779           0 :         if(pList->GetWrdSttExceptList()->find(_sTemp) != pList->GetWrdSttExceptList()->end() )
    1780           0 :             return true;
    1781             :     }
    1782             : 
    1783             :     // If it still could not be found here, then keep on searching
    1784           8 :     if(nTmpKey1 != eLang && (pLangTable->find(aLanguageTag.reset(nTmpKey1)) != pLangTable->end() ||
    1785           0 :                 CreateLanguageFile(aLanguageTag, false)))
    1786             :     {
    1787             :         //the language is available - so bring it on
    1788           0 :         SvxAutoCorrectLanguageLists* pList = pLangTable->find(aLanguageTag)->second;
    1789           0 :         if(pList->GetWrdSttExceptList()->find(sTemp) != pList->GetWrdSttExceptList()->end() )
    1790           0 :             return true;
    1791             :     }
    1792             : 
    1793          16 :     if(nTmpKey2 != eLang && (pLangTable->find(aLanguageTag.reset(nTmpKey2)) != pLangTable->end() ||
    1794           8 :                 CreateLanguageFile(aLanguageTag, false)))
    1795             :     {
    1796             :         //the language is available - so bring it on
    1797           0 :         SvxAutoCorrectLanguageLists* pList = pLangTable->find(aLanguageTag)->second;
    1798           0 :         if(pList->GetWrdSttExceptList()->find(sTemp) != pList->GetWrdSttExceptList()->end() )
    1799           0 :             return true;
    1800             :     }
    1801             : 
    1802          16 :     if(pLangTable->find(aLanguageTag.reset(LANGUAGE_UNDETERMINED)) != pLangTable->end() ||
    1803           8 :             CreateLanguageFile(aLanguageTag, false))
    1804             :     {
    1805             :         //the language is available - so bring it on
    1806           0 :         SvxAutoCorrectLanguageLists* pList = pLangTable->find(aLanguageTag)->second;
    1807           0 :         if(pList->GetWrdSttExceptList()->find(sTemp) != pList->GetWrdSttExceptList()->end() )
    1808           0 :             return true;
    1809             :     }
    1810          16 :     return false;
    1811             : }
    1812             : 
    1813           0 : static bool lcl_FindAbbreviation(const SvStringsISortDtor* pList, const OUString& sWord)
    1814             : {
    1815           0 :     OUString sAbk('~');
    1816           0 :     SvStringsISortDtor::const_iterator it = pList->find( sAbk );
    1817           0 :     sal_uInt16 nPos = it - pList->begin();
    1818           0 :     if( nPos < pList->size() )
    1819             :     {
    1820           0 :         OUString sLowerWord(sWord.toAsciiLowerCase());
    1821           0 :         OUString pAbk;
    1822           0 :         for( sal_uInt16 n = nPos;
    1823           0 :                 n < pList->size() &&
    1824           0 :                 '~' == ( pAbk = (*pList)[ n ])[ 0 ];
    1825             :             ++n )
    1826             :         {
    1827             :             // ~ and ~. are not allowed!
    1828           0 :             if( 2 < pAbk.getLength() && pAbk.getLength() - 1 <= sWord.getLength() )
    1829             :             {
    1830           0 :                 OUString sLowerAbk(pAbk.toAsciiLowerCase());
    1831           0 :                 for (sal_Int32 i = sLowerAbk.getLength(), ii = sLowerWord.getLength(); i;)
    1832             :                 {
    1833           0 :                     if( !--i )      // agrees
    1834           0 :                         return true;
    1835             : 
    1836           0 :                     if( sLowerAbk[i] != sLowerWord[--ii])
    1837           0 :                         break;
    1838           0 :                 }
    1839             :             }
    1840           0 :         }
    1841             :     }
    1842             :     OSL_ENSURE( !(nPos && '~' == (*pList)[ --nPos ][ 0 ] ),
    1843             :             "Wrongly sorted exception list?" );
    1844           0 :     return false;
    1845             : }
    1846             : 
    1847           0 : bool SvxAutoCorrect::FindInCplSttExceptList(LanguageType eLang,
    1848             :                                 const OUString& sWord, bool bAbbreviation)
    1849             : {
    1850           0 :     LanguageTag aLanguageTag( eLang);
    1851             : 
    1852             :     /* TODO-BCP47: did I mention terrible horrible uglyness? */
    1853             : 
    1854             :     // First search for eLang, then US-English -> English
    1855             :     // and last in LANGUAGE_UNDETERMINED
    1856           0 :     LanguageType nTmpKey1 = eLang & 0x7ff, // the main language in many cases DE
    1857           0 :                  nTmpKey2 = eLang & 0x3ff; // otherwise for example EN
    1858           0 :     OUString sTemp( sWord );
    1859             : 
    1860           0 :     if(pLangTable->find(aLanguageTag) != pLangTable->end() || CreateLanguageFile(aLanguageTag, false))
    1861             :     {
    1862             :         //the language is available - so bring it on
    1863           0 :         const SvStringsISortDtor* pList = pLangTable->find(aLanguageTag)->second->GetCplSttExceptList();
    1864           0 :         if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->find(sTemp) != pList->end() )
    1865           0 :             return true;
    1866             :     }
    1867             : 
    1868             :     // If it still could not be found here, then keep on searching
    1869           0 :     if(nTmpKey1 != eLang && (pLangTable->find(aLanguageTag.reset(nTmpKey1)) != pLangTable->end() ||
    1870           0 :                 CreateLanguageFile(aLanguageTag, false)))
    1871             :     {
    1872           0 :         const SvStringsISortDtor* pList = pLangTable->find(aLanguageTag)->second->GetCplSttExceptList();
    1873           0 :         if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->find(sTemp) != pList->end() )
    1874           0 :             return true;
    1875             :     }
    1876             : 
    1877           0 :     if(nTmpKey2 != eLang && (pLangTable->find(aLanguageTag.reset(nTmpKey2)) != pLangTable->end() ||
    1878           0 :                 CreateLanguageFile(aLanguageTag, false)))
    1879             :     {
    1880             :         //the language is available - so bring it on
    1881           0 :         const SvStringsISortDtor* pList = pLangTable->find(aLanguageTag)->second->GetCplSttExceptList();
    1882           0 :         if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->find(sTemp) != pList->end() )
    1883           0 :             return true;
    1884             :     }
    1885             : 
    1886           0 :     if(pLangTable->find(aLanguageTag.reset(LANGUAGE_UNDETERMINED)) != pLangTable->end() ||
    1887           0 :             CreateLanguageFile(aLanguageTag, false))
    1888             :     {
    1889             :         //the language is available - so bring it on
    1890           0 :         const SvStringsISortDtor* pList = pLangTable->find(aLanguageTag)->second->GetCplSttExceptList();
    1891           0 :         if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->find(sTemp) != pList->end() )
    1892           0 :             return true;
    1893             :     }
    1894           0 :     return false;
    1895             : }
    1896             : 
    1897          48 : OUString SvxAutoCorrect::GetAutoCorrFileName( const LanguageTag& rLanguageTag,
    1898             :                                             bool bNewFile, bool bTst, bool bUnlocalized ) const
    1899             : {
    1900          96 :     OUString sRet, sExt( rLanguageTag.getBcp47() );
    1901          48 :     if (bUnlocalized)
    1902             :     {
    1903             :         // we don't want variant, so we'll take "fr" instead of "fr-CA" for example
    1904           6 :         ::std::vector< OUString > vecFallBackStrings = rLanguageTag.getFallbackStrings(false);
    1905           6 :         if (!vecFallBackStrings.empty())
    1906           2 :            sExt = vecFallBackStrings[0];
    1907             :     }
    1908             : 
    1909          48 :     sExt = "_" + sExt + ".dat";
    1910          48 :     if( bNewFile )
    1911          36 :         ( sRet = sUserAutoCorrFile )  += sExt;
    1912          12 :     else if( !bTst )
    1913          12 :         ( sRet = sShareAutoCorrFile )  += sExt;
    1914             :     else
    1915             :     {
    1916             :         // test first in the user directory - if not exist, then
    1917           0 :         ( sRet = sUserAutoCorrFile ) += sExt;
    1918           0 :         if( !FStatHelper::IsDocument( sRet ))
    1919           0 :             ( sRet = sShareAutoCorrFile ) += sExt;
    1920             :     }
    1921          96 :     return sRet;
    1922             : }
    1923             : 
    1924           0 : SvxAutoCorrectLanguageLists::SvxAutoCorrectLanguageLists(
    1925             :                 SvxAutoCorrect& rParent,
    1926             :                 const OUString& rShareAutoCorrectFile,
    1927             :                 const OUString& rUserAutoCorrectFile)
    1928             : :   sShareAutoCorrFile( rShareAutoCorrectFile ),
    1929             :     sUserAutoCorrFile( rUserAutoCorrectFile ),
    1930             :     aModifiedDate( Date::EMPTY ),
    1931             :     aModifiedTime( tools::Time::EMPTY ),
    1932             :     aLastCheckTime( tools::Time::EMPTY ),
    1933             :     pCplStt_ExcptLst( 0 ),
    1934             :     pWrdStt_ExcptLst( 0 ),
    1935             :     pAutocorr_List( 0 ),
    1936             :     rAutoCorrect(rParent),
    1937           0 :     nFlags(0)
    1938             : {
    1939           0 : }
    1940             : 
    1941           0 : SvxAutoCorrectLanguageLists::~SvxAutoCorrectLanguageLists()
    1942             : {
    1943           0 :     delete pCplStt_ExcptLst;
    1944           0 :     delete pWrdStt_ExcptLst;
    1945           0 :     delete pAutocorr_List;
    1946           0 : }
    1947             : 
    1948           0 : bool SvxAutoCorrectLanguageLists::IsFileChanged_Imp()
    1949             : {
    1950             :     // Access the file system only every 2 minutes to check the date stamp
    1951           0 :     bool bRet = false;
    1952             : 
    1953           0 :     tools::Time nMinTime( 0, 2 );
    1954           0 :     tools::Time nAktTime( tools::Time::SYSTEM );
    1955           0 :     if( aLastCheckTime > nAktTime ||                    // overflow?
    1956           0 :         ( nAktTime -= aLastCheckTime ) > nMinTime )     // min time past
    1957             :     {
    1958           0 :         Date aTstDate( Date::EMPTY ); tools::Time aTstTime( tools::Time::EMPTY );
    1959           0 :         if( FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
    1960           0 :                                             &aTstDate, &aTstTime ) &&
    1961           0 :             ( aModifiedDate != aTstDate || aModifiedTime != aTstTime ))
    1962             :         {
    1963           0 :             bRet = true;
    1964             :             // then remove all the lists fast!
    1965           0 :             if( CplSttLstLoad & nFlags && pCplStt_ExcptLst )
    1966           0 :                 delete pCplStt_ExcptLst, pCplStt_ExcptLst = 0;
    1967           0 :             if( WrdSttLstLoad & nFlags && pWrdStt_ExcptLst )
    1968           0 :                 delete pWrdStt_ExcptLst, pWrdStt_ExcptLst = 0;
    1969           0 :             if( ChgWordLstLoad & nFlags && pAutocorr_List )
    1970           0 :                 delete pAutocorr_List, pAutocorr_List = 0;
    1971           0 :             nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad );
    1972             :         }
    1973           0 :         aLastCheckTime = tools::Time( tools::Time::SYSTEM );
    1974             :     }
    1975           0 :     return bRet;
    1976             : }
    1977             : 
    1978           0 : void SvxAutoCorrectLanguageLists::LoadXMLExceptList_Imp(
    1979             :                                         SvStringsISortDtor*& rpLst,
    1980             :                                         const sal_Char* pStrmName,
    1981             :                                         SotStorageRef& rStg)
    1982             : {
    1983           0 :     if( rpLst )
    1984           0 :         rpLst->clear();
    1985             :     else
    1986           0 :         rpLst = new SvStringsISortDtor;
    1987             : 
    1988             :     {
    1989           0 :         OUString sStrmName( pStrmName, strlen(pStrmName), RTL_TEXTENCODING_MS_1252 );
    1990           0 :         OUString sTmp( sStrmName );
    1991             : 
    1992           0 :         if( rStg.Is() && rStg->IsStream( sStrmName ) )
    1993             :         {
    1994             :             SvStorageStreamRef xStrm = rStg->OpenSotStream( sTmp,
    1995           0 :                 ( STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE ) );
    1996           0 :             if( SVSTREAM_OK != xStrm->GetError())
    1997             :             {
    1998           0 :                 xStrm.Clear();
    1999           0 :                 rStg.Clear();
    2000           0 :                 RemoveStream_Imp( sStrmName );
    2001             :             }
    2002             :             else
    2003             :             {
    2004             :                 uno::Reference< uno::XComponentContext > xContext =
    2005           0 :                     comphelper::getProcessComponentContext();
    2006             : 
    2007           0 :                 xml::sax::InputSource aParserInput;
    2008           0 :                 aParserInput.sSystemId = sStrmName;
    2009             : 
    2010           0 :                 xStrm->Seek( 0L );
    2011           0 :                 xStrm->SetBufferSize( 8 * 1024 );
    2012           0 :                 aParserInput.aInputStream = new utl::OInputStreamWrapper( *xStrm );
    2013             : 
    2014             :                 // get filter
    2015           0 :                 uno::Reference< xml::sax::XFastDocumentHandler > xFilter = new SvXMLExceptionListImport ( xContext, *rpLst );
    2016             : 
    2017             :                 // connect parser and filter
    2018           0 :                 uno::Reference< xml::sax::XFastParser > xParser = xml::sax::FastParser::create( xContext );
    2019           0 :                 uno::Reference< xml::sax::XFastTokenHandler > xTokenHandler = static_cast< xml::sax::XFastTokenHandler* >( new SvXMLAutoCorrectTokenHandler );
    2020           0 :                 xParser->setFastDocumentHandler( xFilter );
    2021           0 :                 xParser->registerNamespace( "http://openoffice.org/2001/block-list", SvXMLAutoCorrectToken::NAMESPACE );
    2022           0 :                 xParser->setTokenHandler( xTokenHandler );
    2023             : 
    2024             :                 // parse
    2025             :                 try
    2026             :                 {
    2027           0 :                     xParser->parseStream( aParserInput );
    2028             :                 }
    2029           0 :                 catch( const xml::sax::SAXParseException& )
    2030             :                 {
    2031             :                     // re throw ?
    2032             :                 }
    2033           0 :                 catch( const xml::sax::SAXException& )
    2034             :                 {
    2035             :                     // re throw ?
    2036             :                 }
    2037           0 :                 catch( const io::IOException& )
    2038             :                 {
    2039             :                     // re throw ?
    2040           0 :                 }
    2041           0 :             }
    2042             :         }
    2043             : 
    2044             :         // Set time stamp
    2045             :         FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
    2046           0 :                                         &aModifiedDate, &aModifiedTime );
    2047           0 :         aLastCheckTime = tools::Time( tools::Time::SYSTEM );
    2048             :     }
    2049             : 
    2050           0 : }
    2051             : 
    2052           0 : void SvxAutoCorrectLanguageLists::SaveExceptList_Imp(
    2053             :                             const SvStringsISortDtor& rLst,
    2054             :                             const sal_Char* pStrmName,
    2055             :                             SotStorageRef &rStg,
    2056             :                             bool bConvert )
    2057             : {
    2058           0 :     if( rStg.Is() )
    2059             :     {
    2060           0 :         OUString sStrmName( pStrmName, strlen(pStrmName), RTL_TEXTENCODING_MS_1252 );
    2061           0 :         if( rLst.empty() )
    2062             :         {
    2063           0 :             rStg->Remove( sStrmName );
    2064           0 :             rStg->Commit();
    2065             :         }
    2066             :         else
    2067             :         {
    2068             :             SotStorageStreamRef xStrm = rStg->OpenSotStream( sStrmName,
    2069           0 :                     ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) );
    2070           0 :             if( xStrm.Is() )
    2071             :             {
    2072           0 :                 xStrm->SetSize( 0 );
    2073           0 :                 xStrm->SetBufferSize( 8192 );
    2074           0 :                 OUString aMime( "text/xml" );
    2075           0 :                 uno::Any aAny;
    2076           0 :                 aAny <<= aMime;
    2077           0 :                 xStrm->SetProperty( OUString("MediaType"), aAny );
    2078             : 
    2079             : 
    2080             :                 uno::Reference< uno::XComponentContext > xContext =
    2081           0 :                     comphelper::getProcessComponentContext();
    2082             : 
    2083           0 :                 uno::Reference < xml::sax::XWriter > xWriter  = xml::sax::Writer::create(xContext);
    2084           0 :                 uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *xStrm );
    2085           0 :                 xWriter->setOutputStream(xOut);
    2086             : 
    2087           0 :                 uno::Reference < xml::sax::XDocumentHandler > xHandler(xWriter, UNO_QUERY_THROW);
    2088           0 :                 SvXMLExceptionListExport aExp( xContext, rLst, sStrmName, xHandler );
    2089             : 
    2090           0 :                 aExp.exportDoc( XML_BLOCK_LIST );
    2091             : 
    2092           0 :                 xStrm->Commit();
    2093           0 :                 if( xStrm->GetError() == SVSTREAM_OK )
    2094             :                 {
    2095           0 :                     xStrm.Clear();
    2096           0 :                     if (!bConvert)
    2097             :                     {
    2098           0 :                         rStg->Commit();
    2099           0 :                         if( SVSTREAM_OK != rStg->GetError() )
    2100             :                         {
    2101           0 :                             rStg->Remove( sStrmName );
    2102           0 :                             rStg->Commit();
    2103             :                         }
    2104             :                     }
    2105           0 :                 }
    2106           0 :             }
    2107           0 :         }
    2108             :     }
    2109           0 : }
    2110             : 
    2111           0 : SvxAutocorrWordList* SvxAutoCorrectLanguageLists::LoadAutocorrWordList()
    2112             : {
    2113           0 :     if( pAutocorr_List )
    2114           0 :         pAutocorr_List->DeleteAndDestroyAll();
    2115             :     else
    2116           0 :         pAutocorr_List = new SvxAutocorrWordList();
    2117             : 
    2118             :     try
    2119             :     {
    2120           0 :         uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sShareAutoCorrFile, embed::ElementModes::READ );
    2121           0 :         OUString aXMLWordListName( pXMLImplAutocorr_ListStr, strlen(pXMLImplAutocorr_ListStr), RTL_TEXTENCODING_MS_1252 );
    2122           0 :         uno::Reference < io::XStream > xStrm = xStg->openStreamElement( aXMLWordListName, embed::ElementModes::READ );
    2123           0 :         uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
    2124             : 
    2125           0 :         xml::sax::InputSource aParserInput;
    2126           0 :         aParserInput.sSystemId = aXMLWordListName;
    2127           0 :         aParserInput.aInputStream = xStrm->getInputStream();
    2128             : 
    2129             :         // get parser
    2130           0 :         uno::Reference< xml::sax::XFastParser > xParser = xml::sax::FastParser::create(xContext);
    2131             :         SAL_INFO("editeng", "AutoCorrect Import" );
    2132           0 :         uno::Reference< xml::sax::XFastDocumentHandler > xFilter = new SvXMLAutoCorrectImport( xContext, pAutocorr_List, rAutoCorrect, xStg );
    2133           0 :         uno::Reference< xml::sax::XFastTokenHandler > xTokenHandler = static_cast< xml::sax::XFastTokenHandler* >( new SvXMLAutoCorrectTokenHandler );
    2134             : 
    2135             :         // connect parser and filter
    2136           0 :         xParser->setFastDocumentHandler( xFilter );
    2137           0 :         xParser->registerNamespace( "http://openoffice.org/2001/block-list", SvXMLAutoCorrectToken::NAMESPACE );
    2138           0 :         xParser->setTokenHandler(xTokenHandler);
    2139             : 
    2140             :         // parse
    2141           0 :         xParser->parseStream( aParserInput );
    2142             :     }
    2143           0 :     catch ( const uno::Exception& )
    2144             :     {
    2145             :     }
    2146             : 
    2147             :     // Set time stamp
    2148             :     FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
    2149           0 :                                     &aModifiedDate, &aModifiedTime );
    2150           0 :     aLastCheckTime = tools::Time( tools::Time::SYSTEM );
    2151             : 
    2152           0 :     return pAutocorr_List;
    2153             : }
    2154             : 
    2155           0 : void SvxAutoCorrectLanguageLists::SetAutocorrWordList( SvxAutocorrWordList* pList )
    2156             : {
    2157           0 :     if( pAutocorr_List && pList != pAutocorr_List )
    2158           0 :         delete pAutocorr_List;
    2159           0 :     pAutocorr_List = pList;
    2160           0 :     if( !pAutocorr_List )
    2161             :     {
    2162             :         OSL_ENSURE( false, "No valid list" );
    2163           0 :         pAutocorr_List = new SvxAutocorrWordList();
    2164             :     }
    2165           0 :     nFlags |= ChgWordLstLoad;
    2166           0 : }
    2167             : 
    2168           0 : const SvxAutocorrWordList* SvxAutoCorrectLanguageLists::GetAutocorrWordList()
    2169             : {
    2170           0 :     if( !( ChgWordLstLoad & nFlags ) || IsFileChanged_Imp() )
    2171           0 :         SetAutocorrWordList( LoadAutocorrWordList() );
    2172           0 :     return pAutocorr_List;
    2173             : }
    2174             : 
    2175           0 : SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetCplSttExceptList()
    2176             : {
    2177           0 :     if( !( CplSttLstLoad & nFlags ) || IsFileChanged_Imp() )
    2178           0 :         SetCplSttExceptList( LoadCplSttExceptList() );
    2179           0 :     return pCplStt_ExcptLst;
    2180             : }
    2181             : 
    2182           0 : bool SvxAutoCorrectLanguageLists::AddToCplSttExceptList(const OUString& rNew)
    2183             : {
    2184           0 :     bool aRet = false;
    2185           0 :     if( !rNew.isEmpty() && GetCplSttExceptList()->insert( rNew ).second )
    2186             :     {
    2187           0 :         MakeUserStorage_Impl();
    2188           0 :         SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
    2189             : 
    2190           0 :         SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
    2191             : 
    2192           0 :         xStg = 0;
    2193             :         // Set time stamp
    2194             :         FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
    2195           0 :                                             &aModifiedDate, &aModifiedTime );
    2196           0 :         aLastCheckTime = tools::Time( tools::Time::SYSTEM );
    2197           0 :         aRet = true;
    2198             :     }
    2199           0 :     return aRet;
    2200             : }
    2201             : 
    2202           0 : bool SvxAutoCorrectLanguageLists::AddToWrdSttExceptList(const OUString& rNew)
    2203             : {
    2204           0 :     bool aRet = false;
    2205           0 :     SvStringsISortDtor* pExceptList = LoadWrdSttExceptList();
    2206           0 :     if( !rNew.isEmpty() && pExceptList && pExceptList->insert( rNew ).second )
    2207             :     {
    2208           0 :         MakeUserStorage_Impl();
    2209           0 :         SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
    2210             : 
    2211           0 :         SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
    2212             : 
    2213           0 :         xStg = 0;
    2214             :         // Set time stamp
    2215             :         FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
    2216           0 :                                             &aModifiedDate, &aModifiedTime );
    2217           0 :         aLastCheckTime = tools::Time( tools::Time::SYSTEM );
    2218           0 :         aRet = true;
    2219             :     }
    2220           0 :     return aRet;
    2221             : }
    2222             : 
    2223           0 : SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadCplSttExceptList()
    2224             : {
    2225             :     try
    2226             :     {
    2227           0 :         SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, sal_True );
    2228           0 :         OUString sTemp ( pXMLImplCplStt_ExcptLstStr );
    2229           0 :         if( xStg.Is() && xStg->IsContained( sTemp ) )
    2230           0 :             LoadXMLExceptList_Imp( pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
    2231             :     }
    2232           0 :     catch (const css::ucb::ContentCreationException&)
    2233             :     {
    2234             :     }
    2235           0 :     return pCplStt_ExcptLst;
    2236             : }
    2237             : 
    2238           0 : void SvxAutoCorrectLanguageLists::SaveCplSttExceptList()
    2239             : {
    2240           0 :     MakeUserStorage_Impl();
    2241           0 :     SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
    2242             : 
    2243           0 :     SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
    2244             : 
    2245           0 :     xStg = 0;
    2246             : 
    2247             :     // Set time stamp
    2248             :     FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
    2249           0 :                                             &aModifiedDate, &aModifiedTime );
    2250           0 :     aLastCheckTime = tools::Time( tools::Time::SYSTEM );
    2251           0 : }
    2252             : 
    2253           0 : void SvxAutoCorrectLanguageLists::SetCplSttExceptList( SvStringsISortDtor* pList )
    2254             : {
    2255           0 :     if( pCplStt_ExcptLst && pList != pCplStt_ExcptLst )
    2256           0 :         delete pCplStt_ExcptLst;
    2257             : 
    2258           0 :     pCplStt_ExcptLst = pList;
    2259           0 :     if( !pCplStt_ExcptLst )
    2260             :     {
    2261             :         OSL_ENSURE( false, "No valid list" );
    2262           0 :         pCplStt_ExcptLst = new SvStringsISortDtor;
    2263             :     }
    2264           0 :     nFlags |= CplSttLstLoad;
    2265           0 : }
    2266             : 
    2267           0 : SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadWrdSttExceptList()
    2268             : {
    2269             :     try
    2270             :     {
    2271           0 :         SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, sal_True );
    2272           0 :         OUString sTemp ( pXMLImplWrdStt_ExcptLstStr );
    2273           0 :         if( xStg.Is() && xStg->IsContained( sTemp ) )
    2274           0 :             LoadXMLExceptList_Imp( pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
    2275             :     }
    2276           0 :     catch (const css::ucb::ContentCreationException &e)
    2277             :     {
    2278             :         SAL_WARN("editeng", "SvxAutoCorrectLanguageLists::LoadWrdSttExceptList: Caught exception: " << e.Message);
    2279             :     }
    2280           0 :     return pWrdStt_ExcptLst;
    2281             : }
    2282             : 
    2283           0 : void SvxAutoCorrectLanguageLists::SaveWrdSttExceptList()
    2284             : {
    2285           0 :     MakeUserStorage_Impl();
    2286           0 :     SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
    2287             : 
    2288           0 :     SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
    2289             : 
    2290           0 :     xStg = 0;
    2291             :     // Set time stamp
    2292             :     FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
    2293           0 :                                             &aModifiedDate, &aModifiedTime );
    2294           0 :     aLastCheckTime = tools::Time( tools::Time::SYSTEM );
    2295           0 : }
    2296             : 
    2297           0 : void SvxAutoCorrectLanguageLists::SetWrdSttExceptList( SvStringsISortDtor* pList )
    2298             : {
    2299           0 :     if( pWrdStt_ExcptLst && pList != pWrdStt_ExcptLst )
    2300           0 :         delete pWrdStt_ExcptLst;
    2301           0 :     pWrdStt_ExcptLst = pList;
    2302           0 :     if( !pWrdStt_ExcptLst )
    2303             :     {
    2304             :         OSL_ENSURE( false, "No valid list" );
    2305           0 :         pWrdStt_ExcptLst = new SvStringsISortDtor;
    2306             :     }
    2307           0 :     nFlags |= WrdSttLstLoad;
    2308           0 : }
    2309             : 
    2310           0 : SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetWrdSttExceptList()
    2311             : {
    2312           0 :     if( !( WrdSttLstLoad & nFlags ) || IsFileChanged_Imp() )
    2313           0 :         SetWrdSttExceptList( LoadWrdSttExceptList() );
    2314           0 :     return pWrdStt_ExcptLst;
    2315             : }
    2316             : 
    2317           0 : void SvxAutoCorrectLanguageLists::RemoveStream_Imp( const OUString& rName )
    2318             : {
    2319           0 :     if( sShareAutoCorrFile != sUserAutoCorrFile )
    2320             :     {
    2321           0 :         SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
    2322           0 :         if( xStg.Is() && SVSTREAM_OK == xStg->GetError() &&
    2323           0 :             xStg->IsStream( rName ) )
    2324             :         {
    2325           0 :             xStg->Remove( rName );
    2326           0 :             xStg->Commit();
    2327             : 
    2328           0 :             xStg = 0;
    2329           0 :         }
    2330             :     }
    2331           0 : }
    2332             : 
    2333           0 : void SvxAutoCorrectLanguageLists::MakeUserStorage_Impl()
    2334             : {
    2335             :     // The conversion needs to happen if the file is already in the user
    2336             :     // directory and is in the old format. Additionally it needs to
    2337             :     // happen when the file is being copied from share to user.
    2338             : 
    2339           0 :     bool bError = false, bConvert = false, bCopy = false;
    2340           0 :     INetURLObject aDest;
    2341           0 :     INetURLObject aSource;
    2342             : 
    2343           0 :     if (sUserAutoCorrFile != sShareAutoCorrFile )
    2344             :     {
    2345           0 :         aSource = INetURLObject ( sShareAutoCorrFile );
    2346           0 :         aDest = INetURLObject ( sUserAutoCorrFile );
    2347           0 :         if ( SotStorage::IsOLEStorage ( sShareAutoCorrFile ) )
    2348             :         {
    2349           0 :             aDest.SetExtension ( OUString("bak") );
    2350           0 :             bConvert = true;
    2351             :         }
    2352           0 :         bCopy = true;
    2353             :     }
    2354           0 :     else if ( SotStorage::IsOLEStorage ( sUserAutoCorrFile ) )
    2355             :     {
    2356           0 :         aSource = INetURLObject ( sUserAutoCorrFile );
    2357           0 :         aDest = INetURLObject ( sUserAutoCorrFile );
    2358           0 :         aDest.SetExtension ( OUString("bak") );
    2359           0 :         bCopy = bConvert = true;
    2360             :     }
    2361           0 :     if (bCopy)
    2362             :     {
    2363             :         try
    2364             :         {
    2365           0 :             OUString sMain(aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ));
    2366           0 :             sal_Unicode cSlash = '/';
    2367           0 :             sal_Int32 nSlashPos = sMain.lastIndexOf(cSlash);
    2368           0 :             sMain = sMain.copy(0, nSlashPos);
    2369           0 :             ::ucbhelper::Content aNewContent( sMain, uno::Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() );
    2370           0 :             Any aAny;
    2371           0 :             TransferInfo aInfo;
    2372           0 :             aInfo.NameClash = NameClash::OVERWRITE;
    2373           0 :             aInfo.NewTitle  = aDest.GetName();
    2374           0 :             aInfo.SourceURL = aSource.GetMainURL( INetURLObject::DECODE_TO_IURI );
    2375           0 :             aInfo.MoveData  = sal_False;
    2376           0 :             aAny <<= aInfo;
    2377           0 :             aNewContent.executeCommand( OUString (  "transfer"  ), aAny);
    2378             :         }
    2379           0 :         catch (...)
    2380             :         {
    2381           0 :             bError = true;
    2382             :         }
    2383             :     }
    2384           0 :     if (bConvert && !bError)
    2385             :     {
    2386           0 :         SotStorageRef xSrcStg = new SotStorage( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), STREAM_READ, sal_True );
    2387           0 :         SotStorageRef xDstStg = new SotStorage( sUserAutoCorrFile, STREAM_WRITE, sal_True );
    2388             : 
    2389           0 :         if( xSrcStg.Is() && xDstStg.Is() )
    2390             :         {
    2391           0 :             OUString sXMLWord     ( pXMLImplWrdStt_ExcptLstStr );
    2392           0 :             OUString sXMLSentence ( pXMLImplCplStt_ExcptLstStr );
    2393           0 :             SvStringsISortDtor  *pTmpWordList = NULL;
    2394             : 
    2395           0 :             if (xSrcStg->IsContained( sXMLWord ) )
    2396           0 :                 LoadXMLExceptList_Imp( pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xSrcStg );
    2397             : 
    2398           0 :             if (pTmpWordList)
    2399             :             {
    2400           0 :                 SaveExceptList_Imp( *pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xDstStg, true );
    2401           0 :                 pTmpWordList->clear();
    2402           0 :                 pTmpWordList = NULL;
    2403             :             }
    2404             : 
    2405             : 
    2406           0 :             if (xSrcStg->IsContained( sXMLSentence ) )
    2407           0 :                 LoadXMLExceptList_Imp( pTmpWordList, pXMLImplCplStt_ExcptLstStr, xSrcStg );
    2408             : 
    2409           0 :             if (pTmpWordList)
    2410             :             {
    2411           0 :                 SaveExceptList_Imp( *pTmpWordList, pXMLImplCplStt_ExcptLstStr, xDstStg, true );
    2412           0 :                 pTmpWordList->clear();
    2413             :             }
    2414             : 
    2415           0 :             GetAutocorrWordList();
    2416           0 :             MakeBlocklist_Imp( *xDstStg );
    2417           0 :             sShareAutoCorrFile = sUserAutoCorrFile;
    2418           0 :             xDstStg = 0;
    2419             :             try
    2420             :             {
    2421           0 :                 ::ucbhelper::Content aContent ( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), uno::Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
    2422           0 :                 aContent.executeCommand ( OUString( "delete" ), makeAny ( true ) );
    2423             :             }
    2424           0 :             catch (...)
    2425             :             {
    2426           0 :             }
    2427           0 :         }
    2428             :     }
    2429           0 :     else if( bCopy && !bError )
    2430           0 :         sShareAutoCorrFile = sUserAutoCorrFile;
    2431           0 : }
    2432             : 
    2433           0 : bool SvxAutoCorrectLanguageLists::MakeBlocklist_Imp( SvStorage& rStg )
    2434             : {
    2435           0 :     OUString sStrmName( pXMLImplAutocorr_ListStr, strlen(pXMLImplAutocorr_ListStr), RTL_TEXTENCODING_MS_1252 );
    2436           0 :     bool bRet = true, bRemove = !pAutocorr_List || pAutocorr_List->empty();
    2437           0 :     if( !bRemove )
    2438             :     {
    2439             :         SvStorageStreamRef refList = rStg.OpenSotStream( sStrmName,
    2440           0 :                     ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) );
    2441           0 :         if( refList.Is() )
    2442             :         {
    2443           0 :             refList->SetSize( 0 );
    2444           0 :             refList->SetBufferSize( 8192 );
    2445           0 :             OUString aPropName( "MediaType" );
    2446           0 :             OUString aMime( "text/xml" );
    2447           0 :             uno::Any aAny;
    2448           0 :             aAny <<= aMime;
    2449           0 :             refList->SetProperty( aPropName, aAny );
    2450             : 
    2451             :             uno::Reference< uno::XComponentContext > xContext =
    2452           0 :                 comphelper::getProcessComponentContext();
    2453             : 
    2454           0 :             uno::Reference < xml::sax::XWriter > xWriter = xml::sax::Writer::create(xContext);
    2455           0 :             uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *refList );
    2456           0 :             xWriter->setOutputStream(xOut);
    2457             : 
    2458           0 :             uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY);
    2459           0 :             SvXMLAutoCorrectExport aExp( xContext, pAutocorr_List, sStrmName, xHandler );
    2460             : 
    2461           0 :             aExp.exportDoc( XML_BLOCK_LIST );
    2462             : 
    2463           0 :             refList->Commit();
    2464           0 :             bRet = SVSTREAM_OK == refList->GetError();
    2465           0 :             if( bRet )
    2466             :             {
    2467           0 :                 refList.Clear();
    2468           0 :                 rStg.Commit();
    2469           0 :                 if( SVSTREAM_OK != rStg.GetError() )
    2470             :                 {
    2471           0 :                     bRemove = true;
    2472           0 :                     bRet = false;
    2473             :                 }
    2474           0 :             }
    2475             :         }
    2476             :         else
    2477           0 :             bRet = false;
    2478             :     }
    2479             : 
    2480           0 :     if( bRemove )
    2481             :     {
    2482           0 :         rStg.Remove( sStrmName );
    2483           0 :         rStg.Commit();
    2484             :     }
    2485             : 
    2486           0 :     return bRet;
    2487             : }
    2488             : 
    2489           0 : bool SvxAutoCorrectLanguageLists::MakeCombinedChanges( std::vector<SvxAutocorrWord>& aNewEntries, std::vector<SvxAutocorrWord>& aDeleteEntries )
    2490             : {
    2491             :     // First get the current list!
    2492           0 :     GetAutocorrWordList();
    2493             : 
    2494           0 :     MakeUserStorage_Impl();
    2495           0 :     SotStorageRef xStorage = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
    2496             : 
    2497           0 :     bool bRet = xStorage.Is() && SVSTREAM_OK == xStorage->GetError();
    2498             : 
    2499           0 :     if( bRet )
    2500             :     {
    2501           0 :         for ( sal_uInt32 i=0; i < aDeleteEntries.size(); i++ )
    2502             :         {
    2503           0 :             SvxAutocorrWord aWordToDelete = aDeleteEntries[i];
    2504           0 :             SvxAutocorrWord *pFoundEntry = pAutocorr_List->FindAndRemove( &aWordToDelete );
    2505           0 :             if( pFoundEntry )
    2506             :             {
    2507           0 :                 if( !pFoundEntry->IsTextOnly() )
    2508             :                 {
    2509           0 :                     OUString aName( aWordToDelete.GetShort() );
    2510           0 :                     if (xStorage->IsOLEStorage())
    2511           0 :                         aName = EncryptBlockName_Imp(aName);
    2512             :                     else
    2513           0 :                         GeneratePackageName ( aWordToDelete.GetShort(), aName );
    2514             : 
    2515           0 :                     if( xStorage->IsContained( aName ) )
    2516             :                     {
    2517           0 :                         xStorage->Remove( aName );
    2518           0 :                         bRet = xStorage->Commit();
    2519           0 :                     }
    2520             :                 }
    2521           0 :                 delete pFoundEntry;
    2522             :             }
    2523           0 :         }
    2524             : 
    2525           0 :         for ( sal_uInt32 i=0; i < aNewEntries.size(); i++ )
    2526             :         {
    2527           0 :             SvxAutocorrWord *pWordToAdd = new SvxAutocorrWord( aNewEntries[i].GetShort(), aNewEntries[i].GetLong(), true );
    2528           0 :             SvxAutocorrWord *pRemoved = pAutocorr_List->FindAndRemove( pWordToAdd );
    2529           0 :             if( pRemoved )
    2530             :             {
    2531           0 :                 if( !pRemoved->IsTextOnly() )
    2532             :                 {
    2533             :                     // Still have to remove the Storage
    2534           0 :                     OUString sStorageName( pWordToAdd->GetShort() );
    2535           0 :                     if (xStorage->IsOLEStorage())
    2536           0 :                         sStorageName = EncryptBlockName_Imp(sStorageName);
    2537             :                     else
    2538           0 :                         GeneratePackageName ( pWordToAdd->GetShort(), sStorageName);
    2539             : 
    2540           0 :                     if( xStorage->IsContained( sStorageName ) )
    2541           0 :                         xStorage->Remove( sStorageName );
    2542             :                 }
    2543           0 :                 delete pRemoved;
    2544             :             }
    2545           0 :             bRet = pAutocorr_List->Insert( pWordToAdd );
    2546             : 
    2547           0 :             if ( !bRet )
    2548             :             {
    2549           0 :                 delete pWordToAdd;
    2550           0 :                 break;
    2551             :             }
    2552             :         }
    2553             : 
    2554           0 :         if ( bRet )
    2555             :         {
    2556           0 :             bRet = MakeBlocklist_Imp( *xStorage );
    2557             :         }
    2558             :     }
    2559           0 :     return bRet;
    2560             : }
    2561             : 
    2562           0 : bool SvxAutoCorrectLanguageLists::PutText( const OUString& rShort, const OUString& rLong )
    2563             : {
    2564             :     // First get the current list!
    2565           0 :     GetAutocorrWordList();
    2566             : 
    2567           0 :     MakeUserStorage_Impl();
    2568           0 :     SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
    2569             : 
    2570           0 :     bool bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError();
    2571             : 
    2572             :     // Update the word list
    2573           0 :     if( bRet )
    2574             :     {
    2575           0 :         SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, rLong, true );
    2576           0 :         SvxAutocorrWord *pRemove = pAutocorr_List->FindAndRemove( pNew );
    2577           0 :         if( pRemove )
    2578             :         {
    2579           0 :             if( !pRemove->IsTextOnly() )
    2580             :             {
    2581             :                 // Still have to remove the Storage
    2582           0 :                 OUString sStgNm( rShort );
    2583           0 :                 if (xStg->IsOLEStorage())
    2584           0 :                     sStgNm = EncryptBlockName_Imp(sStgNm);
    2585             :                 else
    2586           0 :                     GeneratePackageName ( rShort, sStgNm);
    2587             : 
    2588           0 :                 if( xStg->IsContained( sStgNm ) )
    2589           0 :                     xStg->Remove( sStgNm );
    2590             :             }
    2591           0 :             delete pRemove;
    2592             :         }
    2593             : 
    2594           0 :         if( pAutocorr_List->Insert( pNew ) )
    2595             :         {
    2596           0 :             bRet = MakeBlocklist_Imp( *xStg );
    2597           0 :             xStg = 0;
    2598             :         }
    2599             :         else
    2600             :         {
    2601           0 :             delete pNew;
    2602           0 :             bRet = false;
    2603             :         }
    2604             :     }
    2605           0 :     return bRet;
    2606             : }
    2607             : 
    2608           0 : bool SvxAutoCorrectLanguageLists::PutText( const OUString& rShort,
    2609             :                                                SfxObjectShell& rShell )
    2610             : {
    2611             :     // First get the current list!
    2612           0 :     GetAutocorrWordList();
    2613             : 
    2614           0 :     MakeUserStorage_Impl();
    2615             : 
    2616           0 :     bool bRet = false;
    2617           0 :     OUString sLong;
    2618             :     try
    2619             :     {
    2620           0 :         uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sUserAutoCorrFile, embed::ElementModes::READWRITE );
    2621           0 :         bRet = rAutoCorrect.PutText( xStg, sUserAutoCorrFile, rShort, rShell, sLong );
    2622           0 :         xStg = 0;
    2623             : 
    2624             :         // Update the word list
    2625           0 :         if( bRet )
    2626             :         {
    2627           0 :             SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, sLong, false );
    2628           0 :             if( pAutocorr_List->Insert( pNew ) )
    2629             :             {
    2630           0 :                 SotStorageRef xStor = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
    2631           0 :                 MakeBlocklist_Imp( *xStor );
    2632             :             }
    2633             :             else
    2634           0 :                 delete pNew;
    2635           0 :         }
    2636             :     }
    2637           0 :     catch ( const uno::Exception& )
    2638             :     {
    2639             :     }
    2640             : 
    2641           0 :     return bRet;
    2642             : }
    2643             : 
    2644             : // Delete an entry
    2645           0 : bool SvxAutoCorrectLanguageLists::DeleteText( const OUString& rShort )
    2646             : {
    2647             :     // First get the current list!
    2648           0 :     GetAutocorrWordList();
    2649             : 
    2650           0 :     MakeUserStorage_Impl();
    2651             : 
    2652           0 :     SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
    2653           0 :     bool bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError();
    2654           0 :     if( bRet )
    2655             :     {
    2656           0 :         SvxAutocorrWord aTmp( rShort, rShort );
    2657           0 :         SvxAutocorrWord *pFnd = pAutocorr_List->FindAndRemove( &aTmp );
    2658           0 :         if( pFnd )
    2659             :         {
    2660           0 :             if( !pFnd->IsTextOnly() )
    2661             :             {
    2662           0 :                 OUString aName( rShort );
    2663           0 :                 if (xStg->IsOLEStorage())
    2664           0 :                     aName = EncryptBlockName_Imp(aName);
    2665             :                 else
    2666           0 :                     GeneratePackageName ( rShort, aName );
    2667           0 :                 if( xStg->IsContained( aName ) )
    2668             :                 {
    2669           0 :                     xStg->Remove( aName );
    2670           0 :                     bRet = xStg->Commit();
    2671           0 :                 }
    2672             : 
    2673             :             }
    2674           0 :             delete pFnd;
    2675           0 :             MakeBlocklist_Imp( *xStg );
    2676           0 :             xStg = 0;
    2677             :         }
    2678             :         else
    2679           0 :             bRet = false;
    2680             :     }
    2681           0 :     return bRet;
    2682             : }
    2683             : 
    2684             : // Keep the list sorted ...
    2685           0 : bool CompareSvxAutocorrWordList::operator()( SvxAutocorrWord* const& lhs, SvxAutocorrWord* const& rhs ) const
    2686             : {
    2687           0 :     CollatorWrapper& rCmp = ::GetCollatorWrapper();
    2688           0 :     return rCmp.compareString( lhs->GetShort(), rhs->GetShort() ) < 0;
    2689             : }
    2690             : 
    2691           0 : SvxAutocorrWordList::~SvxAutocorrWordList()
    2692             : {
    2693           0 :     DeleteAndDestroyAll();
    2694           0 : }
    2695             : 
    2696           0 : void SvxAutocorrWordList::DeleteAndDestroyAll()
    2697             : {
    2698           0 :     for( SvxAutocorrWordList_Hash::const_iterator it = maHash.begin(); it != maHash.end(); ++it )
    2699           0 :         delete it->second;
    2700           0 :     maHash.clear();
    2701             : 
    2702           0 :     for( SvxAutocorrWordList_Set::const_iterator it2 = maSet.begin(); it2 != maSet.end(); ++it2 )
    2703           0 :         delete *it2;
    2704           0 :     maSet.clear();
    2705           0 : }
    2706             : 
    2707             : // returns true if inserted
    2708           0 : bool SvxAutocorrWordList::Insert(SvxAutocorrWord *pWord) const
    2709             : {
    2710           0 :     if ( maSet.empty() ) // use the hash
    2711             :     {
    2712           0 :         OUString aShort( pWord->GetShort() );
    2713           0 :         return maHash.insert( std::pair<OUString, SvxAutocorrWord *>( aShort, pWord ) ).second;
    2714             :     }
    2715             :     else
    2716           0 :         return maSet.insert( pWord ).second;
    2717             : }
    2718             : 
    2719           0 : void SvxAutocorrWordList::LoadEntry(const OUString& sWrong, const OUString& sRight, bool bOnlyTxt)
    2720             : {
    2721           0 :     SvxAutocorrWord* pNew = new SvxAutocorrWord( sWrong, sRight, bOnlyTxt );
    2722           0 :     if( !Insert( pNew ) )
    2723           0 :         delete pNew;
    2724           0 : }
    2725             : 
    2726           0 : bool SvxAutocorrWordList::empty() const
    2727             : {
    2728           0 :     return maHash.empty() && maSet.empty();
    2729             : }
    2730             : 
    2731           0 : SvxAutocorrWord *SvxAutocorrWordList::FindAndRemove(SvxAutocorrWord *pWord)
    2732             : {
    2733           0 :     SvxAutocorrWord *pMatch = NULL;
    2734             : 
    2735           0 :     if ( maSet.empty() ) // use the hash
    2736             :     {
    2737           0 :         SvxAutocorrWordList_Hash::iterator it = maHash.find( pWord->GetShort() );
    2738           0 :         if( it != maHash.end() )
    2739             :         {
    2740           0 :             pMatch = it->second;
    2741           0 :             maHash.erase (it);
    2742             :         }
    2743             :     }
    2744             :     else
    2745             :     {
    2746           0 :         SvxAutocorrWordList_Set::iterator it = maSet.find( pWord );
    2747           0 :         if( it != maSet.end() )
    2748             :         {
    2749           0 :             pMatch = *it;
    2750           0 :             maSet.erase (it);
    2751             :         }
    2752             :     }
    2753           0 :     return pMatch;
    2754             : }
    2755             : 
    2756             : // return the sorted contents - defer sorting until we have to.
    2757           0 : SvxAutocorrWordList::Content SvxAutocorrWordList::getSortedContent() const
    2758             : {
    2759           0 :     Content aContent;
    2760             : 
    2761             :     // convert from hash to set permanantly
    2762           0 :     if ( maSet.empty() )
    2763             :     {
    2764             :         // This beasty has some O(N log(N)) in a terribly slow ICU collate fn.
    2765           0 :         for( SvxAutocorrWordList_Hash::const_iterator it = maHash.begin(); it != maHash.end(); ++it )
    2766           0 :             maSet.insert( it->second );
    2767           0 :         maHash.clear();
    2768             :     }
    2769           0 :     for( SvxAutocorrWordList_Set::const_iterator it = maSet.begin(); it != maSet.end(); ++it )
    2770           0 :         aContent.push_back( *it );
    2771             : 
    2772           0 :     return aContent;
    2773             : }
    2774             : 
    2775           0 : const SvxAutocorrWord* SvxAutocorrWordList::WordMatches(const SvxAutocorrWord *pFnd,
    2776             :                                       const OUString &rTxt,
    2777             :                                       sal_Int32 &rStt,
    2778             :                                       sal_Int32 nEndPos) const
    2779             : {
    2780           0 :     const OUString& rChk = pFnd->GetShort();
    2781             : 
    2782           0 :     sal_Int32 left_wildcard = rChk.startsWith( ".*" ) ? 2 : 0; // ".*word" pattern?
    2783           0 :     sal_Int32 right_wildcard = rChk.endsWith( ".*" ) ? 2 : 0; // "word.*" pattern?
    2784           0 :     sal_Int32 nSttWdPos = nEndPos;
    2785             : 
    2786           0 :     if ( nEndPos >= rChk.getLength() - left_wildcard - right_wildcard )
    2787             :     {
    2788             : 
    2789           0 :         bool bWasWordDelim = false;
    2790           0 :         sal_Int32 nCalcStt = nEndPos - rChk.getLength() + left_wildcard;
    2791           0 :         if( !right_wildcard && ( !nCalcStt || nCalcStt == rStt || left_wildcard ||
    2792           0 :               ( nCalcStt < rStt &&
    2793           0 :                 IsWordDelim( rTxt[ nCalcStt - 1 ] ))) )
    2794             :         {
    2795           0 :             TransliterationWrapper& rCmp = GetIgnoreTranslWrapper();
    2796           0 :             OUString sWord = rTxt.copy(nCalcStt, rChk.getLength() - left_wildcard);
    2797           0 :             if( (!left_wildcard && rCmp.isEqual( rChk, sWord )) || (left_wildcard && rCmp.isEqual( rChk.copy(left_wildcard), sWord) ))
    2798             :             {
    2799           0 :                 rStt = nCalcStt;
    2800           0 :                 if (!left_wildcard)
    2801             :                 {
    2802             :                     // fdo#33899 avoid "1/2", "1/3".. to be replaced by fractions in dates, eg. 1/2/14
    2803           0 :                     if (rTxt.getLength() > nEndPos && rTxt[nEndPos] == '/' && rChk.indexOf('/') != -1)
    2804           0 :                         return NULL;
    2805           0 :                     return pFnd;
    2806             :                 }
    2807             :                 // get the first word delimiter position before the matching ".*word" pattern
    2808           0 :                 while( rStt && !(bWasWordDelim = IsWordDelim( rTxt[ --rStt ])))
    2809             :                     ;
    2810           0 :                 if (bWasWordDelim) rStt++;
    2811           0 :                 OUString left_pattern = rTxt.copy(rStt, nEndPos - rStt - rChk.getLength() + left_wildcard);
    2812             :                 // avoid double spaces before simple "word" replacement
    2813           0 :                 left_pattern += (left_pattern.getLength() == 0 && pFnd->GetLong()[0] == 0x20) ? pFnd->GetLong().copy(1) : pFnd->GetLong();
    2814           0 :                 SvxAutocorrWord* pNew = new SvxAutocorrWord(rTxt.copy(rStt, nEndPos - rStt), left_pattern);
    2815           0 :                 if( Insert( pNew ) ) return pNew; else delete pNew;
    2816           0 :             }
    2817             :         } else
    2818             :         // match "word.*" or ".*word.*" patterns, eg. "i18n.*", ".*---.*", TODO: add transliteration support
    2819           0 :         if ( right_wildcard )
    2820             :         {
    2821             : 
    2822           0 :             OUString sTmp( rChk.copy( left_wildcard, rChk.getLength() - left_wildcard - right_wildcard ) );
    2823             :             // Get the last word delimiter position
    2824             :             bool not_suffix;
    2825             : 
    2826           0 :             while( nSttWdPos && !(bWasWordDelim = IsWordDelim( rTxt[ --nSttWdPos ])))
    2827             :                 ;
    2828             :             // search the first occurrence (with a left word delimitation, if needed)
    2829           0 :             sal_Int32 nFndPos = -1;
    2830           0 :             do {
    2831           0 :                 nFndPos = rTxt.indexOf( sTmp, nFndPos + 1);
    2832           0 :                 not_suffix = (bWasWordDelim && (nSttWdPos >= nFndPos + sTmp.getLength()));
    2833           0 :             } while ( nFndPos != -1 && (!(left_wildcard || (!left_wildcard && (!nFndPos || IsWordDelim( rTxt[ nFndPos - 1 ])))) || not_suffix));
    2834             : 
    2835           0 :             if ( nFndPos != -1 )
    2836             :             {
    2837           0 :                 sal_Int32 extra_repl = nFndPos + sTmp.getLength() > nEndPos ? 1: 0; // for patterns with terminating characters, eg. "a:"
    2838             : 
    2839           0 :                 if ( left_wildcard )
    2840             :                 {
    2841             :                     // get the first word delimiter position before the matching ".*word.*" pattern
    2842           0 :                     while( nFndPos && !(bWasWordDelim = IsWordDelim( rTxt[ --nFndPos ])))
    2843             :                         ;
    2844           0 :                     if (bWasWordDelim) nFndPos++;
    2845             :                 }
    2846           0 :                 if (nEndPos + extra_repl <= nFndPos)
    2847             :                 {
    2848           0 :                     return 0;
    2849             :                 }
    2850             :                 // store matching pattern and its replacement as a new list item, eg. "i18ns" -> "internationalizations"
    2851           0 :                 OUString aShort = rTxt.copy(nFndPos, nEndPos - nFndPos + extra_repl);
    2852             : 
    2853           0 :                 OUString aLong;
    2854           0 :                 rStt = nFndPos;
    2855           0 :                 if ( !left_wildcard )
    2856             :                 {
    2857           0 :                     sal_Int32 siz = nEndPos - nFndPos - sTmp.getLength();
    2858           0 :                     aLong = pFnd->GetLong() + (siz > 0 ? rTxt.copy(nFndPos + sTmp.getLength(), siz) : "");
    2859             :                 } else {
    2860           0 :                     OUStringBuffer buf;
    2861           0 :                     do {
    2862           0 :                         nSttWdPos = rTxt.indexOf( sTmp, nFndPos);
    2863           0 :                         if (nSttWdPos != -1)
    2864             :                         {
    2865           0 :                             buf.append(rTxt.copy(nFndPos, nSttWdPos - nFndPos)).append(pFnd->GetLong());
    2866           0 :                             nFndPos = nSttWdPos + sTmp.getLength();
    2867             :                         }
    2868             :                     } while (nSttWdPos != -1);
    2869           0 :                     if (nEndPos - nFndPos > extra_repl) buf.append(rTxt.copy(nFndPos, nEndPos - nFndPos));
    2870           0 :                     aLong = buf.makeStringAndClear();
    2871             :                 }
    2872           0 :                 SvxAutocorrWord* pNew = new SvxAutocorrWord(aShort, aLong);
    2873           0 :                 if ( Insert( pNew ) )
    2874             :                 {
    2875           0 :                     if ( IsWordDelim(rTxt[nEndPos]) ) return pNew;
    2876           0 :                 } else delete pNew;
    2877           0 :             }
    2878             :         }
    2879             :     }
    2880           0 :     return NULL;
    2881             : }
    2882             : 
    2883           0 : const SvxAutocorrWord* SvxAutocorrWordList::SearchWordsInList(const OUString& rTxt, sal_Int32& rStt,
    2884             :                                                               sal_Int32 nEndPos) const
    2885             : {
    2886           0 :     for( SvxAutocorrWordList_Hash::const_iterator it = maHash.begin(); it != maHash.end(); ++it )
    2887             :     {
    2888           0 :         if( const SvxAutocorrWord *aTmp = WordMatches( it->second, rTxt, rStt, nEndPos ) )
    2889           0 :             return aTmp;
    2890             :     }
    2891             : 
    2892           0 :     for( SvxAutocorrWordList_Set::const_iterator it2 = maSet.begin(); it2 != maSet.end(); ++it2 )
    2893             :     {
    2894           0 :         if( const SvxAutocorrWord *aTmp = WordMatches( *it2, rTxt, rStt, nEndPos ) )
    2895           0 :             return aTmp;
    2896             :     }
    2897           0 :     return 0;
    2898         669 : }
    2899             : 
    2900             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10