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

Generated by: LCOV version 1.10