xref: /AOO41X/main/editeng/source/misc/svxacorr.cxx (revision 79aad27f7f29270c03e208e3d687e8e3850af11d)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_editeng.hxx"
26 
27 
28 #include <com/sun/star/io/XStream.hpp>
29 #include <com/sun/star/lang/Locale.hpp>
30 #include <tools/urlobj.hxx>
31 #include <tools/table.hxx>
32 #include <i18npool/mslangid.hxx>
33 #include <vcl/svapp.hxx>
34 #include <sot/storinfo.hxx>
35 // fuer die Sort-String-Arrays aus dem SVMEM.HXX
36 #define _SVSTDARR_STRINGSISORTDTOR
37 #define _SVSTDARR_STRINGSDTOR
38 #include <svl/svstdarr.hxx>
39 #include <svl/fstathelper.hxx>
40 #include <svtools/helpopt.hxx>
41 #include <svl/urihelper.hxx>
42 #include <unotools/charclass.hxx>
43 #include <com/sun/star/i18n/UnicodeType.hdl>
44 #include <unotools/collatorwrapper.hxx>
45 #include <com/sun/star/i18n/CollatorOptions.hpp>
46 #include <com/sun/star/i18n/UnicodeScript.hpp>
47 #include <unotools/localedatawrapper.hxx>
48 #include <unotools/transliterationwrapper.hxx>
49 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
50 #include <comphelper/processfactory.hxx>
51 #include <com/sun/star/io/XActiveDataSource.hpp>
52 #include <editeng/editids.hrc>
53 #include <sot/storage.hxx>
54 #include <comphelper/storagehelper.hxx>
55 #include <editeng/udlnitem.hxx>
56 #include <editeng/wghtitem.hxx>
57 #include <editeng/escpitem.hxx>
58 #include <editeng/svxacorr.hxx>
59 #include <editeng/unolingu.hxx>
60 #include <helpid.hrc>
61 #include <comphelper/processfactory.hxx>
62 #include <com/sun/star/xml/sax/InputSource.hpp>
63 #include <com/sun/star/xml/sax/XParser.hpp>
64 #include <unotools/streamwrap.hxx>
65 #include <SvXMLAutoCorrectImport.hxx>
66 #include <SvXMLAutoCorrectExport.hxx>
67 #include <ucbhelper/content.hxx>
68 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
69 #include <com/sun/star/ucb/TransferInfo.hpp>
70 #include <com/sun/star/ucb/NameClash.hpp>
71 #include <xmloff/xmltoken.hxx>
72 #include <vcl/help.hxx>
73 
74 #define CHAR_HARDBLANK      ((sal_Unicode)0x00A0)
75 
76 using namespace ::com::sun::star::ucb;
77 using namespace ::com::sun::star::uno;
78 using namespace ::com::sun::star;
79 using namespace ::xmloff::token;
80 using namespace ::rtl;
81 using namespace ::utl;
82 
83 const int C_NONE                = 0x00;
84 const int C_FULL_STOP           = 0x01;
85 const int C_EXCLAMATION_MARK    = 0x02;
86 const int C_QUESTION_MARK       = 0x04;
87 
88 static const sal_Char pImplWrdStt_ExcptLstStr[]    = "WordExceptList";
89 static const sal_Char pImplCplStt_ExcptLstStr[]    = "SentenceExceptList";
90 static const sal_Char pImplAutocorr_ListStr[]      = "DocumentList";
91 static const sal_Char pXMLImplWrdStt_ExcptLstStr[] = "WordExceptList.xml";
92 static const sal_Char pXMLImplCplStt_ExcptLstStr[] = "SentenceExceptList.xml";
93 static const sal_Char pXMLImplAutocorr_ListStr[]   = "DocumentList.xml";
94 
95 static const sal_Char
96     /* auch bei diesen Anfaengen - Klammern auf und alle Arten von Anf.Zei. */
97     sImplSttSkipChars[] = "\"\'([{\x83\x84\x89\x91\x92\x93\x94",
98     /* auch bei diesen Ende - Klammern auf und alle Arten von Anf.Zei. */
99     sImplEndSkipChars[] = "\"\')]}\x83\x84\x89\x91\x92\x93\x94";
100 
101 // diese Zeichen sind in Worten erlaubt: (fuer FnCptlSttSntnc)
102 static const sal_Char sImplWordChars[] = "-'";
103 
104 void EncryptBlockName_Imp( String& rName );
105 void DecryptBlockName_Imp( String& rName );
106 
107 
108 // FileVersions Nummern fuer die Ersetzungs-/Ausnahmelisten getrennt
109 #define WORDLIST_VERSION_358    1
110 #define EXEPTLIST_VERSION_358   0
111 
112 
113 _SV_IMPL_SORTAR_ALG( SvxAutocorrWordList, SvxAutocorrWordPtr )
114 TYPEINIT0(SvxAutoCorrect)
115 
116 typedef SvxAutoCorrectLanguageLists* SvxAutoCorrectLanguageListsPtr;
DECLARE_TABLE(SvxAutoCorrLanguageTable_Impl,SvxAutoCorrectLanguageListsPtr)117 DECLARE_TABLE( SvxAutoCorrLanguageTable_Impl,  SvxAutoCorrectLanguageListsPtr)
118 
119 DECLARE_TABLE( SvxAutoCorrLastFileAskTable_Impl, long )
120 
121 
122 inline int IsWordDelim( const sal_Unicode c )
123 {
124     return ' ' == c || '\t' == c || 0x0a == c ||
125             0xA0 == c || 0x2011 == c || 0x1 == c;
126 }
127 
IsLowerLetter(sal_Int32 nCharType)128 inline int IsLowerLetter( sal_Int32 nCharType )
129 {
130     return CharClass::isLetterType( nCharType ) &&
131             0 == ( ::com::sun::star::i18n::KCharacterType::UPPER & nCharType);
132 }
IsUpperLetter(sal_Int32 nCharType)133 inline int IsUpperLetter( sal_Int32 nCharType )
134 {
135     return CharClass::isLetterType( nCharType ) &&
136             0 == ( ::com::sun::star::i18n::KCharacterType::LOWER & nCharType);
137 }
138 
lcl_IsUnsupportedUnicodeChar(CharClass & rCC,const String & rTxt,xub_StrLen nStt,xub_StrLen nEnd)139 bool lcl_IsUnsupportedUnicodeChar( CharClass& rCC, const String& rTxt,
140                         xub_StrLen nStt, xub_StrLen nEnd )
141 {
142     for( ; nStt < nEnd; ++nStt )
143     {
144 #if OSL_DEBUG_LEVEL > 1
145         sal_Int32 nCharType;
146         sal_Int32 nChType;
147         nCharType = rCC.getCharacterType( rTxt, nStt );
148         nChType = rCC.getType( rTxt, nStt );
149 #endif
150         short nScript = rCC.getScript( rTxt, nStt );
151         switch( nScript )
152         {
153             case ::com::sun::star::i18n::UnicodeScript_kCJKRadicalsSupplement:
154             case ::com::sun::star::i18n::UnicodeScript_kHangulJamo:
155             case ::com::sun::star::i18n::UnicodeScript_kCJKSymbolPunctuation:
156             case ::com::sun::star::i18n::UnicodeScript_kHiragana:
157             case ::com::sun::star::i18n::UnicodeScript_kKatakana:
158             case ::com::sun::star::i18n::UnicodeScript_kHangulCompatibilityJamo:
159             case ::com::sun::star::i18n::UnicodeScript_kEnclosedCJKLetterMonth:
160             case ::com::sun::star::i18n::UnicodeScript_kCJKCompatibility:
161             case ::com::sun::star::i18n::UnicodeScript_k_CJKUnifiedIdeographsExtensionA:
162             case ::com::sun::star::i18n::UnicodeScript_kCJKUnifiedIdeograph:
163             case ::com::sun::star::i18n::UnicodeScript_kHangulSyllable:
164             case ::com::sun::star::i18n::UnicodeScript_kCJKCompatibilityIdeograph:
165             case ::com::sun::star::i18n::UnicodeScript_kHalfwidthFullwidthForm:
166                 return true;
167             default: ; //do nothing
168         }
169 
170     }
171     return false;
172 }
173 
lcl_IsSymbolChar(CharClass & rCC,const String & rTxt,xub_StrLen nStt,xub_StrLen nEnd)174 sal_Bool lcl_IsSymbolChar( CharClass& rCC, const String& rTxt,
175                         xub_StrLen nStt, xub_StrLen nEnd )
176 {
177     for( ; nStt < nEnd; ++nStt )
178     {
179 #if OSL_DEBUG_LEVEL > 1
180         sal_Int32 nCharType;
181         sal_Int32 nChType;
182         nCharType = rCC.getCharacterType( rTxt, nStt );
183         nChType = rCC.getType( rTxt, nStt );
184 #endif
185         if( ::com::sun::star::i18n::UnicodeType::PRIVATE_USE ==
186                 rCC.getType( rTxt, nStt ))
187             return sal_True;
188     }
189     return sal_False;
190 }
191 
192 
lcl_IsInAsciiArr(const sal_Char * pArr,const sal_Unicode c)193 static sal_Bool lcl_IsInAsciiArr( const sal_Char* pArr, const sal_Unicode c )
194 {
195     sal_Bool bRet = sal_False;
196     for( ; *pArr; ++pArr )
197         if( *pArr == c )
198         {
199             bRet = sal_True;
200             break;
201         }
202     return bRet;
203 }
204 
~SvxAutoCorrDoc()205 SvxAutoCorrDoc::~SvxAutoCorrDoc()
206 {
207 }
208 
209 
210     // wird nach dem austauschen der Zeichen von den Funktionen
211     //  - FnCptlSttWrd
212     //  - FnCptlSttSntnc
213     // gerufen. Dann koennen die Worte ggfs. in die Ausnahmelisten
214     // aufgenommen werden.
SaveCpltSttWord(sal_uLong,xub_StrLen,const String &,sal_Unicode)215 void SvxAutoCorrDoc::SaveCpltSttWord( sal_uLong, xub_StrLen, const String&,
216                                         sal_Unicode )
217 {
218 }
219 
GetLanguage(xub_StrLen,sal_Bool) const220 LanguageType SvxAutoCorrDoc::GetLanguage( xub_StrLen , sal_Bool ) const
221 {
222     return LANGUAGE_SYSTEM;
223 }
224 
225 static ::com::sun::star::uno::Reference<
GetProcessFact()226             ::com::sun::star::lang::XMultiServiceFactory >& GetProcessFact()
227 {
228     static ::com::sun::star::uno::Reference<
229             ::com::sun::star::lang::XMultiServiceFactory > xMSF =
230                                     ::comphelper::getProcessServiceFactory();
231     return xMSF;
232 }
233 
GetAppLang()234 static sal_uInt16 GetAppLang()
235 {
236     return Application::GetSettings().GetLanguage();
237 }
GetLocaleDataWrapper(sal_uInt16 nLang)238 static LocaleDataWrapper& GetLocaleDataWrapper( sal_uInt16 nLang )
239 {
240     static LocaleDataWrapper aLclDtWrp( GetProcessFact(),
241                                         SvxCreateLocale( GetAppLang() ) );
242     ::com::sun::star::lang::Locale aLcl( SvxCreateLocale( nLang ));
243     const ::com::sun::star::lang::Locale& rLcl = aLclDtWrp.getLoadedLocale();
244     if( aLcl.Language != rLcl.Language ||
245         aLcl.Country != rLcl.Country ||
246         aLcl.Variant != rLcl.Variant )
247         aLclDtWrp.setLocale( aLcl );
248     return aLclDtWrp;
249 }
GetIgnoreTranslWrapper()250 static TransliterationWrapper& GetIgnoreTranslWrapper()
251 {
252     static int bIsInit = 0;
253     static TransliterationWrapper aWrp( GetProcessFact(),
254                 ::com::sun::star::i18n::TransliterationModules_IGNORE_KANA |
255                 ::com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH );
256     if( !bIsInit )
257     {
258         aWrp.loadModuleIfNeeded( GetAppLang() );
259         bIsInit = 1;
260     }
261     return aWrp;
262 }
GetCollatorWrapper()263 static CollatorWrapper& GetCollatorWrapper()
264 {
265     static int bIsInit = 0;
266     static CollatorWrapper aCollWrp( GetProcessFact() );
267     if( !bIsInit )
268     {
269         aCollWrp.loadDefaultCollator( SvxCreateLocale( GetAppLang() ), 0 );
270         bIsInit = 1;
271     }
272     return aCollWrp;
273 }
274 
275 
DeleteAndDestroy(sal_uInt16 nP,sal_uInt16 nL)276 void SvxAutocorrWordList::DeleteAndDestroy( sal_uInt16 nP, sal_uInt16 nL )
277 {
278     if( nL )
279     {
280         DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
281         for( sal_uInt16 n=nP; n < nP + nL; n++ )
282             delete *((SvxAutocorrWordPtr*)pData+n);
283         SvPtrarr::Remove( nP, nL );
284     }
285 }
286 
287 
Seek_Entry(const SvxAutocorrWordPtr aE,sal_uInt16 * pP) const288 sal_Bool SvxAutocorrWordList::Seek_Entry( const SvxAutocorrWordPtr aE, sal_uInt16* pP ) const
289 {
290     register sal_uInt16 nO  = SvxAutocorrWordList_SAR::Count(),
291             nM,
292             nU = 0;
293     if( nO > 0 )
294     {
295         CollatorWrapper& rCmp = ::GetCollatorWrapper();
296         nO--;
297         while( nU <= nO )
298         {
299             nM = nU + ( nO - nU ) / 2;
300             long nCmp = rCmp.compareString( aE->GetShort(),
301                         (*((SvxAutocorrWordPtr*)pData + nM))->GetShort() );
302             if( 0 == nCmp )
303             {
304                 if( pP ) *pP = nM;
305                 return sal_True;
306             }
307             else if( 0 < nCmp )
308                 nU = nM + 1;
309             else if( nM == 0 )
310             {
311                 if( pP ) *pP = nU;
312                 return sal_False;
313             }
314             else
315                 nO = nM - 1;
316         }
317     }
318     if( pP ) *pP = nU;
319     return sal_False;
320 }
321 
322 /* -----------------18.11.98 15:28-------------------
323  *
324  * --------------------------------------------------*/
lcl_ClearTable(SvxAutoCorrLanguageTable_Impl & rLangTable)325 void lcl_ClearTable(SvxAutoCorrLanguageTable_Impl& rLangTable)
326 {
327     SvxAutoCorrectLanguageListsPtr pLists = rLangTable.Last();
328     while(pLists)
329     {
330         delete pLists;
331         pLists = rLangTable.Prev();
332     }
333     rLangTable.Clear();
334 }
335 
336 /* -----------------03.11.06 10:15-------------------
337  *
338  * --------------------------------------------------*/
339 
IsAutoCorrectChar(sal_Unicode cChar)340 sal_Bool SvxAutoCorrect::IsAutoCorrectChar( sal_Unicode cChar )
341 {
342     return  cChar == '\0' || cChar == '\t' || cChar == 0x0a ||
343             cChar == ' '  || cChar == '\'' || cChar == '\"' ||
344             cChar == '*'  || cChar == '_'  ||
345             cChar == '.'  || cChar == ','  || cChar == ';' ||
346             cChar == ':'  || cChar == '?' || cChar == '!' || cChar == '/';
347 }
348 
NeedsHardspaceAutocorr(sal_Unicode cChar)349 sal_Bool SvxAutoCorrect::NeedsHardspaceAutocorr( sal_Unicode cChar )
350 {
351     return cChar == ';' || cChar == ':'  || cChar == '?' || cChar == '!' ||
352         cChar == '/' /*case for the urls exception*/;
353 }
354 
355 /* -----------------19.11.98 10:15-------------------
356  *
357  * --------------------------------------------------*/
GetDefaultFlags()358 long SvxAutoCorrect::GetDefaultFlags()
359 {
360     long nRet = Autocorrect
361                     | CptlSttSntnc
362                     | CptlSttWrd
363                     | ChgOrdinalNumber
364                     | ChgToEnEmDash
365                     | AddNonBrkSpace
366                     | ChgWeightUnderl
367                     | SetINetAttr
368                     | ChgQuotes
369                     | SaveWordCplSttLst
370                     | SaveWordWrdSttLst;
371     LanguageType eLang = GetAppLang();
372     switch( eLang )
373     {
374     case LANGUAGE_ENGLISH:
375     case LANGUAGE_ENGLISH_US:
376     case LANGUAGE_ENGLISH_UK:
377     case LANGUAGE_ENGLISH_AUS:
378     case LANGUAGE_ENGLISH_CAN:
379     case LANGUAGE_ENGLISH_NZ:
380     case LANGUAGE_ENGLISH_EIRE:
381     case LANGUAGE_ENGLISH_SAFRICA:
382     case LANGUAGE_ENGLISH_JAMAICA:
383     case LANGUAGE_ENGLISH_CARRIBEAN:
384         nRet &= ~(ChgQuotes|ChgSglQuotes);
385         break;
386     }
387     return nRet;
388 }
389 
390 
SvxAutoCorrect(const String & rShareAutocorrFile,const String & rUserAutocorrFile)391 SvxAutoCorrect::SvxAutoCorrect( const String& rShareAutocorrFile,
392                                 const String& rUserAutocorrFile )
393     : sShareAutoCorrFile( rShareAutocorrFile ),
394     sUserAutoCorrFile( rUserAutocorrFile ),
395     pLangTable( new SvxAutoCorrLanguageTable_Impl ),
396     pLastFileTable( new SvxAutoCorrLastFileAskTable_Impl ),
397     pCharClass( 0 ), bRunNext( false ),
398     cStartDQuote( 0 ), cEndDQuote( 0 ), cStartSQuote( 0 ), cEndSQuote( 0 )
399 {
400     nFlags = SvxAutoCorrect::GetDefaultFlags();
401 
402     cEmDash = ByteString::ConvertToUnicode( '\x97', RTL_TEXTENCODING_MS_1252 );
403     cEnDash = ByteString::ConvertToUnicode( '\x96', RTL_TEXTENCODING_MS_1252 );
404 }
405 
SvxAutoCorrect(const SvxAutoCorrect & rCpy)406 SvxAutoCorrect::SvxAutoCorrect( const SvxAutoCorrect& rCpy )
407 :   sShareAutoCorrFile( rCpy.sShareAutoCorrFile ),
408     sUserAutoCorrFile( rCpy.sUserAutoCorrFile ),
409 
410     aSwFlags( rCpy.aSwFlags ),
411 
412     pLangTable( new SvxAutoCorrLanguageTable_Impl ),
413     pLastFileTable( new SvxAutoCorrLastFileAskTable_Impl ),
414     pCharClass( 0 ), bRunNext( false ),
415 
416     nFlags( rCpy.nFlags & ~(ChgWordLstLoad|CplSttLstLoad|WrdSttLstLoad)),
417     cStartDQuote( rCpy.cStartDQuote ), cEndDQuote( rCpy.cEndDQuote ),
418     cStartSQuote( rCpy.cStartSQuote ), cEndSQuote( rCpy.cEndSQuote ),
419     cEmDash( rCpy.cEmDash ), cEnDash( rCpy.cEnDash )
420 {
421 }
422 
423 
~SvxAutoCorrect()424 SvxAutoCorrect::~SvxAutoCorrect()
425 {
426     lcl_ClearTable(*pLangTable);
427     delete pLangTable;
428     delete pLastFileTable;
429     delete pCharClass;
430 }
431 
_GetCharClass(LanguageType eLang)432 void SvxAutoCorrect::_GetCharClass( LanguageType eLang )
433 {
434     delete pCharClass;
435     pCharClass = new CharClass( SvxCreateLocale( eLang ));
436     eCharClassLang = eLang;
437 }
438 
SetAutoCorrFlag(long nFlag,sal_Bool bOn)439 void SvxAutoCorrect::SetAutoCorrFlag( long nFlag, sal_Bool bOn )
440 {
441     long nOld = nFlags;
442     nFlags = bOn ? nFlags | nFlag
443                  : nFlags & ~nFlag;
444 
445     if( !bOn )
446     {
447         if( (nOld & CptlSttSntnc) != (nFlags & CptlSttSntnc) )
448             nFlags &= ~CplSttLstLoad;
449         if( (nOld & CptlSttWrd) != (nFlags & CptlSttWrd) )
450             nFlags &= ~WrdSttLstLoad;
451         if( (nOld & Autocorrect) != (nFlags & Autocorrect) )
452             nFlags &= ~ChgWordLstLoad;
453     }
454 }
455 
456 
457     // Zwei Grossbuchstaben am Wort-Anfang ??
FnCptlSttWrd(SvxAutoCorrDoc & rDoc,const String & rTxt,xub_StrLen nSttPos,xub_StrLen nEndPos,LanguageType eLang)458 sal_Bool SvxAutoCorrect::FnCptlSttWrd( SvxAutoCorrDoc& rDoc, const String& rTxt,
459                                     xub_StrLen nSttPos, xub_StrLen nEndPos,
460                                     LanguageType eLang )
461 {
462     sal_Bool bRet = sal_False;
463     CharClass& rCC = GetCharClass( eLang );
464 
465     // loesche alle nicht alpanum. Zeichen am Wortanfang/-ende und
466     // teste dann ( erkennt: "(min.", "/min.", usw.)
467     for( ; nSttPos < nEndPos; ++nSttPos )
468         if( rCC.isLetterNumeric( rTxt, nSttPos ))
469             break;
470     for( ; nSttPos < nEndPos; --nEndPos )
471         if( rCC.isLetterNumeric( rTxt, nEndPos - 1 ))
472             break;
473 
474     // Zwei Grossbuchstaben am Wort-Anfang ??
475     if( nSttPos+2 < nEndPos &&
476         IsUpperLetter( rCC.getCharacterType( rTxt, nSttPos )) &&
477         IsUpperLetter( rCC.getCharacterType( rTxt, ++nSttPos )) &&
478         // ist das 3. Zeichen ein klein geschiebenes Alpha-Zeichen
479         IsLowerLetter( rCC.getCharacterType( rTxt, nSttPos +1 )) &&
480         // keine Sonder-Attribute ersetzen
481         0x1 != rTxt.GetChar( nSttPos ) && 0x2 != rTxt.GetChar( nSttPos ))
482     {
483         // teste ob das Wort in einer Ausnahmeliste steht
484         String sWord( rTxt.Copy( nSttPos - 1, nEndPos - nSttPos + 1 ));
485         if( !FindInWrdSttExceptList(eLang, sWord) )
486         {
487             sal_Unicode cSave = rTxt.GetChar( nSttPos );
488             String sChar( cSave );
489             rCC.toLower( sChar );
490             if( sChar.GetChar(0) != cSave && rDoc.ReplaceRange( nSttPos, 1, sChar ))
491             {
492                 if( SaveWordWrdSttLst & nFlags )
493                     rDoc.SaveCpltSttWord( CptlSttWrd, nSttPos, sWord, cSave );
494                 bRet = sal_True;
495             }
496         }
497     }
498     return bRet;
499 }
500 
501 
FnChgOrdinalNumber(SvxAutoCorrDoc & rDoc,const String & rTxt,xub_StrLen nSttPos,xub_StrLen nEndPos,LanguageType eLang)502 sal_Bool SvxAutoCorrect::FnChgOrdinalNumber(
503                                 SvxAutoCorrDoc& rDoc, const String& rTxt,
504                                 xub_StrLen nSttPos, xub_StrLen nEndPos,
505                                 LanguageType eLang )
506 {
507 // 1st, 2nd, 3rd, 4 - 0th
508 // 201th oder 201st
509 // 12th oder 12nd
510     CharClass& rCC = GetCharClass( eLang );
511     sal_Bool bChg = sal_False;
512 
513     for( ; nSttPos < nEndPos; ++nSttPos )
514         if( !lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nSttPos ) ))
515             break;
516     for( ; nSttPos < nEndPos; --nEndPos )
517         if( !lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nEndPos - 1 ) ))
518             break;
519 
520     if( 2 < nEndPos - nSttPos &&
521         rCC.isDigit( rTxt, nEndPos - 3 ) )
522     {
523         static sal_Char __READONLY_DATA
524             sAll[]      = "th",         /* rest */
525             sFirst[]    = "st",         /* 1 */
526             sSecond[]   = "nd",         /* 2 */
527             sThird[]    = "rd";         /* 3 */
528         static const sal_Char* __READONLY_DATA aNumberTab[ 4 ] =
529         {
530             sAll, sFirst, sSecond, sThird
531         };
532 
533         sal_Unicode c = rTxt.GetChar( nEndPos - 3 );
534         if( ( c -= '0' ) > 3 )
535             c = 0;
536 
537         bChg = ( ((sal_Unicode)*((aNumberTab[ c ])+0)) ==
538                                         rTxt.GetChar( nEndPos - 2 ) &&
539                  ((sal_Unicode)*((aNumberTab[ c ])+1)) ==
540                                         rTxt.GetChar( nEndPos - 1 )) ||
541                ( 3 < nEndPos - nSttPos &&
542                 ( ((sal_Unicode)*(sAll+0)) == rTxt.GetChar( nEndPos - 2 ) &&
543                   ((sal_Unicode)*(sAll+1)) == rTxt.GetChar( nEndPos - 1 )));
544 
545         if( bChg )
546         {
547             // dann pruefe mal, ob alle bis zum Start alle Zahlen sind
548             for( xub_StrLen n = nEndPos - 3; nSttPos < n; )
549                 if( !rCC.isDigit( rTxt, --n ) )
550                 {
551                     bChg = !rCC.isLetter( rTxt, n );
552                     break;
553                 }
554 
555             if( bChg )      // dann setze mal das Escapement Attribut
556             {
557                 SvxEscapementItem aSvxEscapementItem( DFLT_ESC_AUTO_SUPER,
558                                                     DFLT_ESC_PROP, SID_ATTR_CHAR_ESCAPEMENT );
559                 rDoc.SetAttr( nEndPos - 2, nEndPos,
560                                 SID_ATTR_CHAR_ESCAPEMENT,
561                                 aSvxEscapementItem);
562             }
563         }
564 
565     }
566     return bChg;
567 }
568 
569 
FnChgToEnEmDash(SvxAutoCorrDoc & rDoc,const String & rTxt,xub_StrLen nSttPos,xub_StrLen nEndPos,LanguageType eLang)570 sal_Bool SvxAutoCorrect::FnChgToEnEmDash(
571                                 SvxAutoCorrDoc& rDoc, const String& rTxt,
572                                 xub_StrLen nSttPos, xub_StrLen nEndPos,
573                                 LanguageType eLang )
574 {
575     sal_Bool bRet = sal_False;
576     CharClass& rCC = GetCharClass( eLang );
577     if (eLang == LANGUAGE_SYSTEM)
578         eLang = GetAppLang();
579     bool bAlwaysUseEmDash = (cEmDash && (eLang == LANGUAGE_RUSSIAN || eLang == LANGUAGE_UKRAINIAN));
580 
581     // ersetze " - " oder " --" durch "enDash"
582     if( cEnDash && 1 < nSttPos && 1 <= nEndPos - nSttPos )
583     {
584         sal_Unicode cCh = rTxt.GetChar( nSttPos );
585         if( '-' == cCh )
586         {
587             if( ' ' == rTxt.GetChar( nSttPos-1 ) &&
588                 '-' == rTxt.GetChar( nSttPos+1 ))
589             {
590                 xub_StrLen n;
591                 for( n = nSttPos+2; n < nEndPos && lcl_IsInAsciiArr(
592                             sImplSttSkipChars,(cCh = rTxt.GetChar( n )));
593                         ++n )
594                     ;
595 
596                 // found: " --[<AnySttChars>][A-z0-9]
597                 if( rCC.isLetterNumeric( cCh ) )
598                 {
599                     for( n = nSttPos-1; n && lcl_IsInAsciiArr(
600                             sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); )
601                         ;
602 
603                     // found: "[A-z0-9][<AnyEndChars>] --[<AnySttChars>][A-z0-9]
604                     if( rCC.isLetterNumeric( cCh ))
605                     {
606                         rDoc.Delete( nSttPos, nSttPos + 2 );
607                         rDoc.Insert( nSttPos, bAlwaysUseEmDash ? cEmDash : cEnDash );
608                         bRet = sal_True;
609                     }
610                 }
611             }
612         }
613         else if( 3 < nSttPos &&
614                  ' ' == rTxt.GetChar( nSttPos-1 ) &&
615                  '-' == rTxt.GetChar( nSttPos-2 ))
616         {
617             xub_StrLen n, nLen = 1, nTmpPos = nSttPos - 2;
618             if( '-' == ( cCh = rTxt.GetChar( nTmpPos-1 )) )
619             {
620                 --nTmpPos;
621                 ++nLen;
622                 cCh = rTxt.GetChar( nTmpPos-1 );
623             }
624             if( ' ' == cCh )
625             {
626                 for( n = nSttPos; n < nEndPos && lcl_IsInAsciiArr(
627                             sImplSttSkipChars,(cCh = rTxt.GetChar( n )));
628                         ++n )
629                     ;
630 
631                 // found: " - [<AnySttChars>][A-z0-9]
632                 if( rCC.isLetterNumeric( cCh ) )
633                 {
634                     cCh = ' ';
635                     for( n = nTmpPos-1; n && lcl_IsInAsciiArr(
636                             sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); )
637                             ;
638                     // found: "[A-z0-9][<AnyEndChars>] - [<AnySttChars>][A-z0-9]
639                     if( rCC.isLetterNumeric( cCh ))
640                     {
641                         rDoc.Delete( nTmpPos, nTmpPos + nLen );
642                         rDoc.Insert( nTmpPos, bAlwaysUseEmDash ? cEmDash : cEnDash );
643                         bRet = sal_True;
644                     }
645                 }
646             }
647         }
648     }
649 
650     // Replace [A-z0-9]--[A-z0-9] double dash with "emDash" or "enDash".
651     // Finnish and Hungarian use enDash instead of emDash.
652     bool bEnDash = (eLang == LANGUAGE_HUNGARIAN || eLang == LANGUAGE_FINNISH);
653     if( ((cEmDash && !bEnDash) || (cEnDash && bEnDash)) && 4 <= nEndPos - nSttPos )
654     {
655         String sTmp( rTxt.Copy( nSttPos, nEndPos - nSttPos ) );
656         xub_StrLen nFndPos = sTmp.SearchAscii( "--" );
657         if( STRING_NOTFOUND != nFndPos && nFndPos &&
658             nFndPos + 2 < sTmp.Len() &&
659             ( rCC.isLetterNumeric( sTmp, nFndPos - 1 ) ||
660               lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nFndPos - 1 ) )) &&
661             ( rCC.isLetterNumeric( sTmp, nFndPos + 2 ) ||
662             lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nFndPos + 2 ) )))
663         {
664             nSttPos = nSttPos + nFndPos;
665             rDoc.Delete( nSttPos, nSttPos + 2 );
666             rDoc.Insert( nSttPos, (bEnDash ? cEnDash : cEmDash) );
667             bRet = sal_True;
668         }
669     }
670     return bRet;
671 }
672 
FnAddNonBrkSpace(SvxAutoCorrDoc & rDoc,const String & rTxt,xub_StrLen,xub_StrLen nEndPos,LanguageType eLang)673 sal_Bool SvxAutoCorrect::FnAddNonBrkSpace(
674                                 SvxAutoCorrDoc& rDoc, const String& rTxt,
675                                 xub_StrLen, xub_StrLen nEndPos,
676                                 LanguageType eLang )
677 {
678     bool bRet = false;
679 
680     CharClass& rCC = GetCharClass( eLang );
681     const lang::Locale rLocale = rCC.getLocale( );
682 
683     if ( rLocale.Language == OUString::createFromAscii( "fr" ) )
684     {
685         bool bFrCA = rLocale.Country == OUString::createFromAscii( "CA" );
686         OUString allChars = OUString::createFromAscii( ":;!?" );
687         OUString chars( allChars );
688         if ( bFrCA )
689             chars = OUString::createFromAscii( ":" );
690 
691         sal_Unicode cChar = rTxt.GetChar( nEndPos );
692         bool bHasSpace = chars.indexOf( sal_Unicode( cChar ) ) != -1;
693         bool bIsSpecial = allChars.indexOf( sal_Unicode( cChar ) ) != -1;
694         if ( bIsSpecial )
695         {
696             // Get the last word delimiter position
697             xub_StrLen nSttWdPos = nEndPos;
698             while( nSttWdPos && !IsWordDelim( rTxt.GetChar( --nSttWdPos )))
699                 ;
700 
701             // Check the presence of "://" in the word
702             xub_StrLen nStrPos = rTxt.Search( String::CreateFromAscii( "://" ), nSttWdPos + 1 );
703             if ( STRING_NOTFOUND == nStrPos && nEndPos > 0 )
704             {
705                 // Check the previous char
706                 sal_Unicode cPrevChar = rTxt.GetChar( nEndPos - 1 );
707                 if ( ( chars.indexOf( sal_Unicode( cPrevChar ) ) == -1 ) && cPrevChar != '\t' )
708                 {
709                     // Remove any previous normal space
710                     xub_StrLen nPos = nEndPos - 1;
711                     while ( cPrevChar == ' ' || cPrevChar == CHAR_HARDBLANK )
712                     {
713                         if ( nPos == 0 ) break;
714                         nPos--;
715                         cPrevChar = rTxt.GetChar( nPos );
716                     }
717 
718                     if ( nPos != 0 )
719                     {
720                         nPos++;
721                         if ( nEndPos - nPos > 0 )
722                             rDoc.Delete( nPos, nEndPos );
723 
724                         // Add the non-breaking space at the end pos
725                         if ( bHasSpace )
726                             rDoc.Insert( nPos, CHAR_HARDBLANK );
727                         bRunNext = true;
728                         bRet = true;
729                     }
730                 }
731                 else if ( chars.indexOf( sal_Unicode( cPrevChar ) ) != -1 )
732                     bRunNext = true;
733             }
734         }
735         else if ( cChar == '/' && nEndPos > 1 && rTxt.Len() > (nEndPos - 1) )
736         {
737             // Remove the hardspace right before to avoid formatting URLs
738             sal_Unicode cPrevChar = rTxt.GetChar( nEndPos - 1 );
739             sal_Unicode cMaybeSpaceChar = rTxt.GetChar( nEndPos - 2 );
740             if ( cPrevChar == ':' && cMaybeSpaceChar == CHAR_HARDBLANK )
741             {
742                 rDoc.Delete( nEndPos - 2, nEndPos - 1 );
743                 bRet = true;
744             }
745         }
746     }
747 
748     return bRet;
749 }
750 
FnSetINetAttr(SvxAutoCorrDoc & rDoc,const String & rTxt,xub_StrLen nSttPos,xub_StrLen nEndPos,LanguageType eLang)751 sal_Bool SvxAutoCorrect::FnSetINetAttr( SvxAutoCorrDoc& rDoc, const String& rTxt,
752                                     xub_StrLen nSttPos, xub_StrLen nEndPos,
753                                     LanguageType eLang )
754 {
755     String sURL( URIHelper::FindFirstURLInText( rTxt, nSttPos, nEndPos,
756                                                 GetCharClass( eLang ) ));
757     sal_Bool bRet = 0 != sURL.Len();
758     if( bRet )          // also Attribut setzen:
759         rDoc.SetINetAttr( nSttPos, nEndPos, sURL );
760     return bRet;
761 }
762 
763 
FnChgWeightUnderl(SvxAutoCorrDoc & rDoc,const String & rTxt,xub_StrLen,xub_StrLen nEndPos,LanguageType eLang)764 sal_Bool SvxAutoCorrect::FnChgWeightUnderl( SvxAutoCorrDoc& rDoc, const String& rTxt,
765                                         xub_StrLen, xub_StrLen nEndPos,
766                                         LanguageType eLang )
767 {
768     // Bedingung:
769     //  Am Anfang:  _ oder * hinter Space mit nachfolgenden !Space
770     //  Am Ende:    _ oder * vor Space (Worttrenner?)
771 
772     sal_Unicode c, cInsChar = rTxt.GetChar( nEndPos );  // unterstreichen oder fett
773     if( ++nEndPos != rTxt.Len() &&
774         !IsWordDelim( rTxt.GetChar( nEndPos ) ) )
775         return sal_False;
776 
777     --nEndPos;
778 
779     sal_Bool bAlphaNum = sal_False;
780     xub_StrLen nPos = nEndPos, nFndPos = STRING_NOTFOUND;
781     CharClass& rCC = GetCharClass( eLang );
782 
783     while( nPos )
784     {
785         switch( c = rTxt.GetChar( --nPos ) )
786         {
787         case '_':
788         case '*':
789             if( c == cInsChar )
790             {
791                 if( bAlphaNum && nPos+1 < nEndPos && ( !nPos ||
792                     IsWordDelim( rTxt.GetChar( nPos-1 ))) &&
793                     !IsWordDelim( rTxt.GetChar( nPos+1 )))
794                         nFndPos = nPos;
795                 else
796                     // Bedingung ist nicht erfuellt, also abbrechen
797                     nFndPos = STRING_NOTFOUND;
798                 nPos = 0;
799             }
800             break;
801         default:
802             if( !bAlphaNum )
803                 bAlphaNum = rCC.isLetterNumeric( rTxt, nPos );
804         }
805     }
806 
807     if( STRING_NOTFOUND != nFndPos )
808     {
809         // ueber den gefundenen Bereich das Attribut aufspannen und
810         // das gefunde und am Ende stehende Zeichen loeschen
811         if( '*' == cInsChar )           // Fett
812         {
813             SvxWeightItem aSvxWeightItem( WEIGHT_BOLD, SID_ATTR_CHAR_WEIGHT );
814             rDoc.SetAttr( nFndPos + 1, nEndPos,
815                             SID_ATTR_CHAR_WEIGHT,
816                             aSvxWeightItem);
817         }
818         else                            // unterstrichen
819         {
820             SvxUnderlineItem aSvxUnderlineItem( UNDERLINE_SINGLE, SID_ATTR_CHAR_UNDERLINE );
821             rDoc.SetAttr( nFndPos + 1, nEndPos,
822                             SID_ATTR_CHAR_UNDERLINE,
823                             aSvxUnderlineItem);
824         }
825         rDoc.Delete( nEndPos, nEndPos + 1 );
826         rDoc.Delete( nFndPos, nFndPos + 1 );
827     }
828 
829     return STRING_NOTFOUND != nFndPos;
830 }
831 
832 
FnCptlSttSntnc(SvxAutoCorrDoc & rDoc,const String & rTxt,sal_Bool bNormalPos,xub_StrLen nSttPos,xub_StrLen nEndPos,LanguageType eLang)833 sal_Bool SvxAutoCorrect::FnCptlSttSntnc( SvxAutoCorrDoc& rDoc,
834                                     const String& rTxt, sal_Bool bNormalPos,
835                                     xub_StrLen nSttPos, xub_StrLen nEndPos,
836                                     LanguageType eLang )
837 {
838     // Grossbuchstabe am Satz-Anfang ??
839     if( !rTxt.Len() || nEndPos <= nSttPos )
840         return sal_False;
841 
842     CharClass& rCC = GetCharClass( eLang );
843     String aText( rTxt );
844     const sal_Unicode *pStart = aText.GetBuffer(),
845                       *pStr = pStart + nEndPos,
846                       *pWordStt = 0,
847                       *pDelim = 0;
848 
849     sal_Bool bAtStart = sal_False, bPrevPara = sal_False;
850     do {
851         --pStr;
852         if( rCC.isLetter(
853                 aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
854         {
855             if( !pWordStt )
856                 pDelim = pStr+1;
857             pWordStt = pStr;
858         }
859         else if( pWordStt &&
860                  !rCC.isDigit(
861                      aText,
862                      sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
863         {
864             if( lcl_IsInAsciiArr( sImplWordChars, *pStr ) &&
865                 pWordStt - 1 == pStr &&
866                 // --> FME 2005-02-14 #i38971#
867                 // l'intallazione at beginning of paragraph. Replaced < by <=
868                 (long)(pStart + 1) <= (long)pStr &&
869                 // <--
870                 rCC.isLetter(
871                     aText,
872                     sal::static_int_cast< xub_StrLen >( pStr-1 - pStart ) ) )
873                 pWordStt = --pStr;
874             else
875                 break;
876         }
877     } while( 0 == ( bAtStart = (pStart == pStr)) );
878 
879 
880     if( !pWordStt ||
881         rCC.isDigit(
882             aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) ||
883         IsUpperLetter(
884             rCC.getCharacterType(
885                 aText,
886                 sal::static_int_cast< xub_StrLen >( pWordStt - pStart ) ) ) ||
887         0x1 == *pWordStt || 0x2 == *pWordStt )
888         return sal_False;       // kein zu ersetzendes Zeichen, oder schon ok
889 
890     // JP 27.10.97: wenn das Wort weniger als 3 Zeichen hat und der Trenner
891     //              ein "Num"-Trenner ist, dann nicht ersetzen!
892     //              Damit wird ein "a.",  "a)", "a-a" nicht ersetzt!
893     if( *pDelim && 2 >= pDelim - pWordStt &&
894         lcl_IsInAsciiArr( ".-)>", *pDelim ) )
895         return sal_False;
896 
897     if( !bAtStart ) // noch kein Absatz Anfang ?
898     {
899         if ( IsWordDelim( *pStr ) )
900         {
901             while( 0 == ( bAtStart = (pStart == pStr--) ) && IsWordDelim( *pStr ))
902                 ;
903         }
904         // Asian full stop, full width full stop, full width exclamation mark
905         // and full width question marks are treated as word delimiters
906         else if ( 0x3002 != *pStr && 0xFF0E != *pStr && 0xFF01 != *pStr &&
907                   0xFF1F != *pStr )
908             return sal_False; // kein gueltiger Trenner -> keine Ersetzung
909     }
910 
911     if( bAtStart )  // am Absatz Anfang ?
912     {
913         // Ueberpruefe den vorherigen Absatz, wenn es diesen gibt.
914         // Wenn ja, dann pruefe auf SatzTrenner am Ende.
915         const String* pPrevPara = rDoc.GetPrevPara( bNormalPos );
916         if( !pPrevPara )
917         {
918             // gueltiger Trenner -> Ersetze
919             String sChar( *pWordStt );
920             rCC.toUpper( sChar );
921             return  sChar != *pWordStt &&
922                     rDoc.ReplaceRange( xub_StrLen( pWordStt - pStart ), 1, sChar );
923         }
924 
925         aText = *pPrevPara;
926         bPrevPara = sal_True;
927         bAtStart = sal_False;
928         pStart = aText.GetBuffer();
929         pStr = pStart + aText.Len();
930 
931         do {            // alle Blanks ueberlesen
932             --pStr;
933             if( !IsWordDelim( *pStr ))
934                 break;
935         } while( 0 == ( bAtStart = (pStart == pStr)) );
936 
937         if( bAtStart )
938             return sal_False;       // kein gueltiger Trenner -> keine Ersetzung
939     }
940 
941     // bis hierhier wurde [ \t]+[A-Z0-9]+ gefunden. Test jetzt auf den
942     // Satztrenner. Es koennen alle 3 vorkommen, aber nicht mehrfach !!
943     const sal_Unicode* pExceptStt = 0;
944     if( !bAtStart )
945     {
946         sal_Bool bWeiter = sal_True;
947         int nFlag = C_NONE;
948         do {
949             switch( *pStr )
950             {
951             // Western and Asian full stop
952             case '.':
953             case 0x3002 :
954             case 0xFF0E :
955                 {
956                     if( nFlag & C_FULL_STOP )
957                         return sal_False;       // kein gueltiger Trenner -> keine Ersetzung
958                     nFlag |= C_FULL_STOP;
959                     pExceptStt = pStr;
960                 }
961                 break;
962             case '!':
963             case 0xFF01 :
964                 {
965                     if( nFlag & C_EXCLAMATION_MARK )
966                         return sal_False;   // kein gueltiger Trenner -> keine Ersetzung
967                     nFlag |= C_EXCLAMATION_MARK;
968                 }
969                 break;
970             case '?':
971             case 0xFF1F :
972                 {
973                     if( nFlag & C_QUESTION_MARK)
974                         return sal_False;       // kein gueltiger Trenner -> keine Ersetzung
975                     nFlag |= C_QUESTION_MARK;
976                 }
977                 break;
978             default:
979                 if( !nFlag )
980                     return sal_False;       // kein gueltiger Trenner -> keine Ersetzung
981                 else
982                     bWeiter = sal_False;
983                 break;
984             }
985 
986             if( bWeiter && pStr-- == pStart )
987             {
988 // !!! wenn am Anfang, dann nie ersetzen.
989 //              if( !nFlag )
990                     return sal_False;       // kein gueltiger Trenner -> keine Ersetzung
991 //              ++pStr;
992 //              break;      // Schleife beenden
993             }
994         } while( bWeiter );
995         if( C_FULL_STOP != nFlag )
996             pExceptStt = 0;
997     }
998 
999     if( 2 > ( pStr - pStart ) )
1000         return sal_False;
1001 
1002     if( !rCC.isLetterNumeric(
1003             aText, sal::static_int_cast< xub_StrLen >( pStr-- - pStart ) ) )
1004     {
1005         sal_Bool bValid = sal_False, bAlphaFnd = sal_False;
1006         const sal_Unicode* pTmpStr = pStr;
1007         while( !bValid )
1008         {
1009             if( rCC.isDigit(
1010                     aText,
1011                     sal::static_int_cast< xub_StrLen >( pTmpStr - pStart ) ) )
1012             {
1013                 bValid = sal_True;
1014                 pStr = pTmpStr - 1;
1015             }
1016             else if( rCC.isLetter(
1017                          aText,
1018                          sal::static_int_cast< xub_StrLen >(
1019                              pTmpStr - pStart ) ) )
1020             {
1021                 if( bAlphaFnd )
1022                 {
1023                     bValid = sal_True;
1024                     pStr = pTmpStr;
1025                 }
1026                 else
1027                     bAlphaFnd = sal_True;
1028             }
1029             else if( bAlphaFnd || IsWordDelim( *pTmpStr ) )
1030                 break;
1031 
1032             if( pTmpStr == pStart )
1033                 break;
1034 
1035             --pTmpStr;
1036         }
1037 
1038         if( !bValid )
1039             return sal_False;       // kein gueltiger Trenner -> keine Ersetzung
1040     }
1041 
1042     sal_Bool bNumericOnly = '0' <= *(pStr+1) && *(pStr+1) <= '9';
1043 
1044     // suche den Anfang vom Wort
1045     while( !IsWordDelim( *pStr ))
1046     {
1047         if( bNumericOnly &&
1048             rCC.isLetter(
1049                 aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
1050             bNumericOnly = sal_False;
1051 
1052         if( pStart == pStr )
1053             break;
1054 
1055         --pStr;
1056     }
1057 
1058     if( bNumericOnly )      // besteht nur aus Zahlen, dann nicht
1059         return sal_False;
1060 
1061     if( IsWordDelim( *pStr ))
1062         ++pStr;
1063 
1064     String sWord;
1065 
1066     // ueberpruefe anhand der Exceptionliste
1067     if( pExceptStt )
1068     {
1069         sWord = String(
1070             pStr, sal::static_int_cast< xub_StrLen >( pExceptStt - pStr + 1 ) );
1071         if( FindInCplSttExceptList(eLang, sWord) )
1072             return sal_False;
1073 
1074         // loesche alle nicht alpanum. Zeichen am Wortanfang/-ende und
1075         // teste dann noch mal ( erkennt: "(min.", "/min.", usw.)
1076         String sTmp( sWord );
1077         while( sTmp.Len() &&
1078                 !rCC.isLetterNumeric( sTmp, 0 ) )
1079             sTmp.Erase( 0, 1 );
1080 
1081         // alle hinteren nicht alphanumerische Zeichen bis auf das
1082         // Letzte entfernen
1083         xub_StrLen nLen = sTmp.Len();
1084         while( nLen && !rCC.isLetterNumeric( sTmp, nLen-1 ) )
1085             --nLen;
1086         if( nLen + 1 < sTmp.Len() )
1087             sTmp.Erase( nLen + 1 );
1088 
1089         if( sTmp.Len() && sTmp.Len() != sWord.Len() &&
1090             FindInCplSttExceptList(eLang, sTmp))
1091             return sal_False;
1092 
1093         if(FindInCplSttExceptList(eLang, sWord, sal_True))
1094             return sal_False;
1095     }
1096 
1097     // Ok, dann ersetze mal
1098     sal_Unicode cSave = *pWordStt;
1099     nSttPos = sal::static_int_cast< xub_StrLen >( pWordStt - rTxt.GetBuffer() );
1100     String sChar( cSave );
1101     rCC.toUpper( sChar );
1102     sal_Bool bRet = sChar.GetChar(0) != cSave && rDoc.ReplaceRange( nSttPos, 1, sChar );
1103 
1104     // das Wort will vielleicht jemand haben
1105     if( bRet && SaveWordCplSttLst & nFlags )
1106         rDoc.SaveCpltSttWord( CptlSttSntnc, nSttPos, sWord, cSave );
1107 
1108     return bRet;
1109 }
1110 //The method below is renamed from _GetQuote to GetQuote by BerryJia for Bug95846 Time:2002-8-13 15:50
GetQuote(sal_Unicode cInsChar,sal_Bool bSttQuote,LanguageType eLang) const1111 sal_Unicode SvxAutoCorrect::GetQuote( sal_Unicode cInsChar, sal_Bool bSttQuote,
1112                                         LanguageType eLang ) const
1113 {
1114     sal_Unicode cRet = bSttQuote ? ( '\"' == cInsChar
1115                                     ? GetStartDoubleQuote()
1116                                     : GetStartSingleQuote() )
1117                                  : ( '\"' == cInsChar
1118                                     ? GetEndDoubleQuote()
1119                                     : GetEndSingleQuote() );
1120     if( !cRet )
1121     {
1122         // dann ueber die Language das richtige Zeichen heraussuchen
1123         if( LANGUAGE_NONE == eLang )
1124             cRet = cInsChar;
1125         else
1126         {
1127             LocaleDataWrapper& rLcl = GetLocaleDataWrapper( eLang );
1128             String sRet( bSttQuote
1129                             ? ( '\"' == cInsChar
1130                                 ? rLcl.getDoubleQuotationMarkStart()
1131                                 : rLcl.getQuotationMarkStart() )
1132                             : ( '\"' == cInsChar
1133                                 ? rLcl.getDoubleQuotationMarkEnd()
1134                                 : rLcl.getQuotationMarkEnd() ));
1135             cRet = sRet.Len() ? sRet.GetChar( 0 ) : cInsChar;
1136         }
1137     }
1138     return cRet;
1139 }
1140 
InsertQuote(SvxAutoCorrDoc & rDoc,xub_StrLen nInsPos,sal_Unicode cInsChar,sal_Bool bSttQuote,sal_Bool bIns)1141 void SvxAutoCorrect::InsertQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos,
1142                                     sal_Unicode cInsChar, sal_Bool bSttQuote,
1143                                     sal_Bool bIns )
1144 {
1145     LanguageType eLang = rDoc.GetLanguage( nInsPos, sal_False );
1146     sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang );
1147 
1148     //JP 13.02.99: damit beim Undo das "einfuegte" Zeichen wieder erscheint,
1149     //              wird es erstmal eingefuegt und dann ueberschrieben
1150     String sChg( cInsChar );
1151     if( bIns )
1152         rDoc.Insert( nInsPos, sChg );
1153     else
1154         rDoc.Replace( nInsPos, sChg );
1155 
1156     //JP 13.08.97: Bug 42477 - bei doppelten Anfuehrungszeichen muss bei
1157     //              franzoesischer Sprache an Anfang ein Leerzeichen dahinter
1158     //              und am Ende ein Leerzeichen dahinter eingefuegt werden.
1159     sChg = cRet;
1160 
1161     if( '\"' == cInsChar )
1162     {
1163         if( LANGUAGE_SYSTEM == eLang )
1164             eLang = GetAppLang();
1165         switch( eLang )
1166         {
1167         case LANGUAGE_FRENCH:
1168         case LANGUAGE_FRENCH_BELGIAN:
1169         case LANGUAGE_FRENCH_CANADIAN:
1170         case LANGUAGE_FRENCH_SWISS:
1171         case LANGUAGE_FRENCH_LUXEMBOURG:
1172             // JP 09.02.99: das zusaetzliche Zeichen immer per Insert einfuegen.
1173             //              Es ueberschreibt nichts!
1174             {
1175                 String s( static_cast< sal_Unicode >(0xA0) );
1176                     // UNICODE code for no break space
1177                 if( rDoc.Insert( bSttQuote ? nInsPos+1 : nInsPos, s ))
1178                 {
1179                     if( !bSttQuote )
1180                         ++nInsPos;
1181                 }
1182             }
1183             break;
1184         }
1185     }
1186 
1187     rDoc.Replace( nInsPos, sChg );
1188 }
1189 
GetQuote(SvxAutoCorrDoc & rDoc,xub_StrLen nInsPos,sal_Unicode cInsChar,sal_Bool bSttQuote)1190 String SvxAutoCorrect::GetQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos,
1191                                 sal_Unicode cInsChar, sal_Bool bSttQuote )
1192 {
1193     LanguageType eLang = rDoc.GetLanguage( nInsPos, sal_False );
1194     sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang );
1195 
1196     String sRet( cRet );
1197     //JP 13.08.97: Bug 42477 - bei doppelten Anfuehrungszeichen muss bei
1198     //              franzoesischer Sprache an Anfang ein Leerzeichen dahinter
1199     //              und am Ende ein Leerzeichen dahinter eingefuegt werden.
1200     if( '\"' == cInsChar )
1201     {
1202         if( LANGUAGE_SYSTEM == eLang )
1203             eLang = GetAppLang();
1204         switch( eLang )
1205         {
1206         case LANGUAGE_FRENCH:
1207         case LANGUAGE_FRENCH_BELGIAN:
1208         case LANGUAGE_FRENCH_CANADIAN:
1209         case LANGUAGE_FRENCH_SWISS:
1210         case LANGUAGE_FRENCH_LUXEMBOURG:
1211             if( bSttQuote )
1212                 sRet += ' ';
1213             else
1214                 sRet.Insert( ' ', 0 );
1215             break;
1216         }
1217     }
1218     return sRet;
1219 }
1220 
AutoCorrect(SvxAutoCorrDoc & rDoc,const String & rTxt,xub_StrLen nInsPos,sal_Unicode cChar,sal_Bool bInsert)1221 sal_uLong SvxAutoCorrect::AutoCorrect( SvxAutoCorrDoc& rDoc, const String& rTxt,
1222                                     xub_StrLen nInsPos, sal_Unicode cChar,
1223                                     sal_Bool bInsert )
1224 {
1225     sal_uLong nRet = 0;
1226     bool bIsNextRun = bRunNext;
1227     bRunNext = false;  // if it was set, then it has to be turned off
1228 
1229     do{                                 // only for middle check loop !!
1230         if( cChar )
1231         {
1232             //JP 10.02.97: doppelte Spaces verhindern
1233             if( nInsPos && ' ' == cChar &&
1234                 IsAutoCorrFlag( IgnoreDoubleSpace ) &&
1235                 ' ' == rTxt.GetChar( nInsPos - 1 ) )
1236             {
1237                 nRet = IgnoreDoubleSpace;
1238                 break;
1239             }
1240 
1241             sal_Bool bSingle = '\'' == cChar;
1242             sal_Bool bIsReplaceQuote =
1243                         (IsAutoCorrFlag( ChgQuotes ) && ('\"' == cChar )) ||
1244                         (IsAutoCorrFlag( ChgSglQuotes ) && bSingle );
1245             if( bIsReplaceQuote )
1246             {
1247                 sal_Unicode cPrev;
1248                 sal_Bool bSttQuote = !nInsPos ||
1249                         IsWordDelim( ( cPrev = rTxt.GetChar( nInsPos-1 ))) ||
1250 // os: #56034# - Warum kein schliessendes Anfuehrungszeichen nach dem Bindestrich?
1251 //                      strchr( "-([{", cPrev ) ||
1252                         lcl_IsInAsciiArr( "([{", cPrev ) ||
1253                         ( cEmDash && cEmDash == cPrev ) ||
1254                         ( cEnDash && cEnDash == cPrev );
1255 
1256                 InsertQuote( rDoc, nInsPos, cChar, bSttQuote, bInsert );
1257                 nRet = bSingle ? ChgSglQuotes : ChgQuotes;
1258                 break;
1259             }
1260 
1261             if( bInsert )
1262                 rDoc.Insert( nInsPos, cChar );
1263             else
1264                 rDoc.Replace( nInsPos, cChar );
1265 
1266             // Hardspaces autocorrection
1267             if ( IsAutoCorrFlag( AddNonBrkSpace ) )
1268             {
1269                 if ( NeedsHardspaceAutocorr( cChar ) &&
1270                     FnAddNonBrkSpace( rDoc, rTxt, 0, nInsPos, rDoc.GetLanguage( nInsPos, sal_False ) ) )
1271                 {
1272                     nRet = AddNonBrkSpace;
1273                 }
1274                 else if ( bIsNextRun && !IsAutoCorrectChar( cChar ) )
1275                 {
1276                     // Remove the NBSP if it wasn't an autocorrection
1277                     if ( nInsPos != 0 && NeedsHardspaceAutocorr( rTxt.GetChar( nInsPos - 1 ) ) &&
1278                             cChar != ' ' && cChar != '\t' && cChar != CHAR_HARDBLANK )
1279                     {
1280                         // Look for the last HARD_SPACE
1281                         xub_StrLen nPos = nInsPos - 1;
1282                         bool bContinue = true;
1283                         while ( bContinue )
1284                         {
1285                             const sal_Unicode cTmpChar = rTxt.GetChar( nPos );
1286                             if ( cTmpChar == CHAR_HARDBLANK )
1287                             {
1288                                 rDoc.Delete( nPos, nPos + 1 );
1289                                 nRet = AddNonBrkSpace;
1290                                 bContinue = false;
1291                             }
1292                             else if ( !NeedsHardspaceAutocorr( cTmpChar ) || nPos == 0 )
1293                                 bContinue = false;
1294                             nPos--;
1295                         }
1296                     }
1297                 }
1298             }
1299         }
1300 
1301         if( !nInsPos )
1302             break;
1303 
1304         xub_StrLen nPos = nInsPos - 1;
1305 
1306         // Bug 19286: nur direkt hinter dem "Wort" aufsetzen
1307         if( IsWordDelim( rTxt.GetChar( nPos )))
1308             break;
1309 
1310         // automatisches Fett oder Unterstreichen setzen?
1311         if( '*' == cChar || '_' == cChar )
1312         {
1313             if( IsAutoCorrFlag( ChgWeightUnderl ) &&
1314                 FnChgWeightUnderl( rDoc, rTxt, 0, nPos+1 ) )
1315                 nRet = ChgWeightUnderl;
1316             break;
1317         }
1318 
1319         while( nPos && !IsWordDelim( rTxt.GetChar( --nPos )))
1320             ;
1321 
1322         // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort
1323         // Kuerzel im Auto
1324         xub_StrLen nCapLttrPos = nPos+1;        // auf das 1. Zeichen
1325         if( !nPos && !IsWordDelim( rTxt.GetChar( 0 )))
1326             --nCapLttrPos;          // Absatz Anfang und kein Blank !
1327 
1328         LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, sal_False );
1329         if( LANGUAGE_SYSTEM == eLang )
1330             eLang = MsLangId::getSystemLanguage();
1331         CharClass& rCC = GetCharClass( eLang );
1332 
1333         // no symbol characters
1334         if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nInsPos ))
1335             break;
1336 
1337         if( IsAutoCorrFlag( Autocorrect ) )
1338         {
1339             const String* pPara = 0;
1340             const String** ppPara = IsAutoCorrFlag(CptlSttSntnc) ? &pPara : 0;
1341 
1342             sal_Bool bChgWord = rDoc.ChgAutoCorrWord( nCapLttrPos, nInsPos,
1343                                                     *this, ppPara );
1344             if( !bChgWord )
1345             {
1346                 // JP 16.06.98: dann versuche mal alle !AlphaNum. Zeichen los zu
1347                 //              werden und teste dann nochmals
1348                 //JP 22.04.99: Bug 63883 - entferne nur die "Klammern Start/-Anfaenge",
1349                 //              alle anderen Zeichen muessen drin bleiben.
1350                 xub_StrLen nCapLttrPos1 = nCapLttrPos, nInsPos1 = nInsPos;
1351                 while( nCapLttrPos1 < nInsPos &&
1352                         lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos1 ) )
1353                         )
1354                         ++nCapLttrPos1;
1355                 while( nCapLttrPos1 < nInsPos1 && nInsPos1 &&
1356                         lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nInsPos1-1 ) )
1357                         )
1358                         --nInsPos1;
1359 
1360                 if( (nCapLttrPos1 != nCapLttrPos || nInsPos1 != nInsPos ) &&
1361                     nCapLttrPos1 < nInsPos1 &&
1362                     rDoc.ChgAutoCorrWord( nCapLttrPos1, nInsPos1, *this, ppPara ))
1363                 {
1364                     bChgWord = sal_True;
1365                     nCapLttrPos = nCapLttrPos1;
1366                 }
1367             }
1368 
1369             if( bChgWord )
1370             {
1371                 nRet = Autocorrect;
1372                 if( pPara )
1373                 {
1374                     xub_StrLen nEnd = nCapLttrPos;
1375                     while( nEnd < pPara->Len() &&
1376                             !IsWordDelim( pPara->GetChar( nEnd )))
1377                         ++nEnd;
1378 
1379                     // Grossbuchstabe am Satz-Anfang ??
1380                     if( IsAutoCorrFlag( CptlSttSntnc ) &&
1381                         FnCptlSttSntnc( rDoc, *pPara, sal_False,
1382                                                 nCapLttrPos, nEnd, eLang ) )
1383                         nRet |= CptlSttSntnc;
1384 
1385                     if( IsAutoCorrFlag( ChgToEnEmDash ) &&
1386                         FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nEnd, eLang ) )
1387                         nRet |= ChgToEnEmDash;
1388                 }
1389                 break;
1390             }
1391         }
1392 
1393         if( ( IsAutoCorrFlag( nRet = ChgOrdinalNumber ) &&
1394                 FnChgOrdinalNumber( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) ||
1395             ( IsAutoCorrFlag( nRet = SetINetAttr ) &&
1396                 ( ' ' == cChar || '\t' == cChar || 0x0a == cChar || !cChar ) &&
1397                 FnSetINetAttr( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) )
1398             ;
1399         else
1400         {
1401             nRet = 0;
1402             bool bUnsupported = lcl_IsUnsupportedUnicodeChar( rCC, rTxt, nCapLttrPos, nInsPos );
1403             // Grossbuchstabe am Satz-Anfang ??
1404             if( !bUnsupported &&
1405                 IsAutoCorrFlag( CptlSttSntnc ) &&
1406                 FnCptlSttSntnc( rDoc, rTxt, sal_True, nCapLttrPos, nInsPos, eLang ) )
1407                 nRet |= CptlSttSntnc;
1408 
1409             // Zwei Grossbuchstaben am Wort-Anfang ??
1410             if( !bUnsupported &&
1411                 IsAutoCorrFlag( CptlSttWrd ) &&
1412                 FnCptlSttWrd( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1413                 nRet |= CptlSttWrd;
1414 
1415             if( IsAutoCorrFlag( ChgToEnEmDash ) &&
1416                 FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1417                 nRet |= ChgToEnEmDash;
1418         }
1419 
1420     } while( sal_False );
1421 
1422     if( nRet )
1423     {
1424         const char* aHelpIds[] =
1425         {
1426             HID_AUTOCORR_HELP_WORD,
1427             HID_AUTOCORR_HELP_SENT,
1428             HID_AUTOCORR_HELP_SENTWORD,
1429             HID_AUTOCORR_HELP_ACORWORD,
1430             "",
1431             HID_AUTOCORR_HELP_ACORSENTWORD,
1432             "",
1433             HID_AUTOCORR_HELP_CHGTOENEMDASH,
1434             HID_AUTOCORR_HELP_WORDENEMDASH,
1435             HID_AUTOCORR_HELP_SENTENEMDASH,
1436             HID_AUTOCORR_HELP_SENTWORDENEMDASH,
1437             HID_AUTOCORR_HELP_ACORWORDENEMDASH,
1438             "",
1439             HID_AUTOCORR_HELP_ACORSENTWORDENEMDASH,
1440             "",
1441             HID_AUTOCORR_HELP_CHGQUOTES,
1442             HID_AUTOCORR_HELP_CHGSGLQUOTES,
1443             HID_AUTOCORR_HELP_SETINETATTR,
1444             HID_AUTOCORR_HELP_INGNOREDOUBLESPACE,
1445             HID_AUTOCORR_HELP_CHGWEIGHTUNDERL,
1446             HID_AUTOCORR_HELP_CHGFRACTIONSYMBOL,
1447             HID_AUTOCORR_HELP_CHGORDINALNUMBER
1448         };
1449 
1450         sal_uLong nHelpId = 0;
1451         if( nRet & ( Autocorrect|CptlSttSntnc|CptlSttWrd|ChgToEnEmDash ) )
1452         {
1453             // von 0 - 15
1454             if( nRet & ChgToEnEmDash )
1455                 nHelpId += 8;
1456             if( nRet & Autocorrect )
1457                 nHelpId += 4;
1458             if( nRet & CptlSttSntnc )
1459                 nHelpId += 2;
1460             if( nRet & CptlSttWrd )
1461                 nHelpId += 1;
1462         }
1463         else
1464         {
1465                  if( nRet & ChgQuotes)          nHelpId = 16;
1466             else if( nRet & ChgSglQuotes)       nHelpId = 17;
1467             else if( nRet & SetINetAttr)        nHelpId = 18;
1468             else if( nRet & IgnoreDoubleSpace)  nHelpId = 19;
1469             else if( nRet & ChgWeightUnderl)    nHelpId = 20;
1470             else if( nRet & AddNonBrkSpace)     nHelpId = 21;
1471             else if( nRet & ChgOrdinalNumber)   nHelpId = 22;
1472         }
1473 
1474         if( nHelpId )
1475         {
1476             nHelpId -= 1;
1477             Application::GetHelp()->OpenHelpAgent( aHelpIds[nHelpId] );
1478         }
1479     }
1480 
1481 
1482     return nRet;
1483 }
1484 
_GetLanguageList(LanguageType eLang)1485 SvxAutoCorrectLanguageLists& SvxAutoCorrect::_GetLanguageList(
1486                                                         LanguageType eLang )
1487 {
1488     if( !pLangTable->IsKeyValid( sal_uLong( eLang )))
1489         CreateLanguageFile( eLang, sal_True);
1490     return *pLangTable->Seek( sal_uLong( eLang ) );
1491 }
1492 
SaveCplSttExceptList(LanguageType eLang)1493 void SvxAutoCorrect::SaveCplSttExceptList( LanguageType eLang )
1494 {
1495     if( pLangTable->IsKeyValid( sal_uLong( eLang )))
1496     {
1497         SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(sal_uLong(eLang));
1498         if( pLists )
1499             pLists->SaveCplSttExceptList();
1500     }
1501 #ifdef DBG_UTIL
1502     else
1503     {
1504         DBG_ERROR("speichern einer leeren Liste?");
1505     }
1506 #endif
1507 }
1508 
SaveWrdSttExceptList(LanguageType eLang)1509 void SvxAutoCorrect::SaveWrdSttExceptList(LanguageType eLang)
1510 {
1511     if(pLangTable->IsKeyValid(sal_uLong(eLang)))
1512     {
1513         SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(sal_uLong(eLang));
1514         if(pLists)
1515             pLists->SaveWrdSttExceptList();
1516     }
1517 #ifdef DBG_UTIL
1518     else
1519     {
1520         DBG_ERROR("speichern einer leeren Liste?");
1521     }
1522 #endif
1523 }
1524 
1525 
1526     // fuegt ein einzelnes Wort hinzu. Die Liste wird sofort
1527     // in die Datei geschrieben!
AddCplSttException(const String & rNew,LanguageType eLang)1528 sal_Bool SvxAutoCorrect::AddCplSttException( const String& rNew,
1529                                         LanguageType eLang )
1530 {
1531     SvxAutoCorrectLanguageListsPtr pLists = 0;
1532     //entweder die richtige Sprache ist vorhanden oder es kommt in die allg. Liste
1533     if( pLangTable->IsKeyValid(sal_uLong(eLang)))
1534         pLists = pLangTable->Seek(sal_uLong(eLang));
1535     else if(pLangTable->IsKeyValid(sal_uLong(LANGUAGE_DONTKNOW))||
1536             CreateLanguageFile(LANGUAGE_DONTKNOW, sal_True))
1537     {
1538         pLists = pLangTable->Seek(sal_uLong(LANGUAGE_DONTKNOW));
1539     }
1540     DBG_ASSERT(pLists, "keine Autokorrekturdatei");
1541     return pLists->AddToCplSttExceptList(rNew);
1542 }
1543 
1544 
1545     // fuegt ein einzelnes Wort hinzu. Die Liste wird sofort
1546     // in die Datei geschrieben!
AddWrtSttException(const String & rNew,LanguageType eLang)1547 sal_Bool SvxAutoCorrect::AddWrtSttException( const String& rNew,
1548                                          LanguageType eLang )
1549 {
1550     SvxAutoCorrectLanguageListsPtr pLists = 0;
1551     //entweder die richtige Sprache ist vorhanden oder es kommt in die allg. Liste
1552     if(pLangTable->IsKeyValid(sal_uLong(eLang)))
1553         pLists = pLangTable->Seek(sal_uLong(eLang));
1554     else if(pLangTable->IsKeyValid(sal_uLong(LANGUAGE_DONTKNOW))||
1555             CreateLanguageFile(LANGUAGE_DONTKNOW, sal_True))
1556         pLists = pLangTable->Seek(sal_uLong(LANGUAGE_DONTKNOW));
1557     DBG_ASSERT(pLists, "keine Autokorrekturdatei");
1558     return pLists->AddToWrdSttExceptList(rNew);
1559 }
1560 
1561 
1562 
1563 
SetUserAutoCorrFileName(const String & rNew)1564 void SvxAutoCorrect::SetUserAutoCorrFileName( const String& rNew )
1565 {
1566     if( sUserAutoCorrFile != rNew )
1567     {
1568         sUserAutoCorrFile = rNew;
1569 
1570         // sind die Listen gesetzt sind, so muessen sie jetzt geloescht
1571         // werden
1572         lcl_ClearTable(*pLangTable);
1573         nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad );
1574     }
1575 }
1576 
SetShareAutoCorrFileName(const String & rNew)1577 void SvxAutoCorrect::SetShareAutoCorrFileName( const String& rNew )
1578 {
1579     if( sShareAutoCorrFile != rNew )
1580     {
1581         sShareAutoCorrFile = rNew;
1582 
1583         // sind die Listen gesetzt sind, so muessen sie jetzt geloescht
1584         // werden
1585         lcl_ClearTable(*pLangTable);
1586         nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad );
1587     }
1588 }
1589 
1590 
GetPrevAutoCorrWord(SvxAutoCorrDoc & rDoc,const String & rTxt,xub_StrLen nPos,String & rWord) const1591 sal_Bool SvxAutoCorrect::GetPrevAutoCorrWord( SvxAutoCorrDoc& rDoc,
1592                                         const String& rTxt, xub_StrLen nPos,
1593                                         String& rWord ) const
1594 {
1595     if( !nPos )
1596         return sal_False;
1597 
1598     xub_StrLen nEnde = nPos;
1599 
1600     // dahinter muss ein Blank oder Tab folgen!
1601     if( ( nPos < rTxt.Len() &&
1602         !IsWordDelim( rTxt.GetChar( nPos ))) ||
1603         IsWordDelim( rTxt.GetChar( --nPos )))
1604         return sal_False;
1605 
1606     while( nPos && !IsWordDelim( rTxt.GetChar( --nPos )))
1607         ;
1608 
1609     // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort
1610     // Kuerzel im Auto
1611     xub_StrLen nCapLttrPos = nPos+1;        // auf das 1. Zeichen
1612     if( !nPos && !IsWordDelim( rTxt.GetChar( 0 )))
1613         --nCapLttrPos;          // Absatz Anfang und kein Blank !
1614 
1615     while( lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos )) )
1616         if( ++nCapLttrPos >= nEnde )
1617             return sal_False;
1618 
1619     // Bug 19285: Symbolzeichen nicht anfassen
1620     // Interresant erst ab 3 Zeichen
1621     if( 3 > nEnde - nCapLttrPos )
1622         return sal_False;
1623 
1624     LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, sal_False );
1625     if( LANGUAGE_SYSTEM == eLang )
1626         eLang = MsLangId::getSystemLanguage();
1627 
1628     SvxAutoCorrect* pThis = (SvxAutoCorrect*)this;
1629     CharClass& rCC = pThis->GetCharClass( eLang );
1630 
1631     if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nEnde ))
1632         return sal_False;
1633 
1634     rWord = rTxt.Copy( nCapLttrPos, nEnde - nCapLttrPos );
1635     return sal_True;
1636 }
1637 
CreateLanguageFile(LanguageType eLang,sal_Bool bNewFile)1638 sal_Bool SvxAutoCorrect::CreateLanguageFile( LanguageType eLang, sal_Bool bNewFile )
1639 {
1640     DBG_ASSERT(!pLangTable->IsKeyValid(sal_uLong(eLang)), "Sprache ist bereits vorhanden");
1641 
1642     String sUserDirFile( GetAutoCorrFileName( eLang, sal_True, sal_False )),
1643            sShareDirFile( sUserDirFile );
1644     SvxAutoCorrectLanguageListsPtr pLists = 0;
1645 
1646     Time nMinTime( 0, 2 ), nAktTime, nLastCheckTime;
1647     sal_uLong nFndPos;
1648     if( TABLE_ENTRY_NOTFOUND !=
1649                     pLastFileTable->SearchKey( sal_uLong( eLang ), &nFndPos ) &&
1650         ( nLastCheckTime.SetTime( pLastFileTable->GetObject( nFndPos )),
1651             nLastCheckTime < nAktTime ) &&
1652         ( nAktTime - nLastCheckTime ) < nMinTime )
1653     {
1654         // no need to test the file, because the last check is not older then
1655         // 2 minutes.
1656         if( bNewFile )
1657         {
1658             sShareDirFile = sUserDirFile;
1659             pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile,
1660                                                         sUserDirFile, eLang );
1661             pLangTable->Insert( sal_uLong(eLang), pLists );
1662             pLastFileTable->Remove( sal_uLong( eLang ) );
1663         }
1664     }
1665     else if( ( FStatHelper::IsDocument( sUserDirFile ) ||
1666                FStatHelper::IsDocument( sShareDirFile =
1667                             GetAutoCorrFileName( eLang, sal_False, sal_False ) ) ) ||
1668         ( sShareDirFile = sUserDirFile, bNewFile ))
1669     {
1670         pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile,
1671                                                     sUserDirFile, eLang );
1672         pLangTable->Insert( sal_uLong(eLang), pLists );
1673         pLastFileTable->Remove( sal_uLong( eLang ) );
1674     }
1675     else if( !bNewFile )
1676     {
1677         if( !pLastFileTable->Insert( sal_uLong( eLang ), nAktTime.GetTime() ))
1678             pLastFileTable->Replace( sal_uLong( eLang ), nAktTime.GetTime() );
1679     }
1680     return pLists != 0;
1681 }
1682 
PutText(const String & rShort,const String & rLong,LanguageType eLang)1683 sal_Bool SvxAutoCorrect::PutText( const String& rShort, const String& rLong,
1684                                 LanguageType eLang )
1685 {
1686     sal_Bool bRet = sal_False;
1687     if( pLangTable->IsKeyValid( sal_uLong(eLang)) || CreateLanguageFile(eLang) )
1688         bRet = pLangTable->Seek( sal_uLong(eLang) )->PutText(rShort, rLong);
1689     return bRet;
1690 }
1691 
1692 
1693     //  - loesche einen Eintrag
DeleteText(const String & rShort,LanguageType eLang)1694 sal_Bool SvxAutoCorrect::DeleteText( const String& rShort, LanguageType eLang )
1695 {
1696     sal_Bool bRet = sal_False;
1697     if( pLangTable->IsKeyValid( sal_uLong( eLang )) )
1698         bRet = pLangTable->Seek( sal_uLong( eLang ))->DeleteText( rShort );
1699     return bRet;
1700 }
1701 
1702 
1703     //  - return den Ersetzungstext (nur fuer SWG-Format, alle anderen
1704     //      koennen aus der Wortliste herausgeholt werden!)
GetLongText(const com::sun::star::uno::Reference<com::sun::star::embed::XStorage> &,const String &,const String &,String &)1705 sal_Bool SvxAutoCorrect::GetLongText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String& , String& )
1706 {
1707     return sal_False;
1708 }
1709 
1710     //  - Text mit Attributierung (kann nur der SWG - SWG-Format!)
PutText(const com::sun::star::uno::Reference<com::sun::star::embed::XStorage> &,const String &,const String &,SfxObjectShell &,String &)1711 sal_Bool SvxAutoCorrect::PutText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String&, SfxObjectShell&,
1712                                 String& )
1713 {
1714     return sal_False;
1715 }
1716 
EncryptBlockName_Imp(String & rName)1717 void EncryptBlockName_Imp( String& rName )
1718 {
1719     xub_StrLen nLen, nPos = 1;
1720     rName.Insert( '#', 0 );
1721     sal_Unicode* pName = rName.GetBufferAccess();
1722     for ( nLen = rName.Len(), ++pName; nPos < nLen; ++nPos, ++pName )
1723     {
1724         if( lcl_IsInAsciiArr( "!/:.\\", *pName ))
1725             *pName &= 0x0f;
1726     }
1727 }
1728 
1729 /* This code is copied from SwXMLTextBlocks::GeneratePackageName */
GeneratePackageName(const String & rShort,String & rPackageName)1730 void GeneratePackageName ( const String& rShort, String& rPackageName )
1731 {
1732     rPackageName = rShort;
1733     xub_StrLen nPos = 0;
1734     sal_Unicode pDelims[] = { '!', '/', ':', '.', '\\', 0 };
1735     ByteString sByte ( rPackageName, RTL_TEXTENCODING_UTF7);
1736     rPackageName = String (sByte, RTL_TEXTENCODING_ASCII_US);
1737     while( STRING_NOTFOUND != ( nPos = rPackageName.SearchChar( pDelims, nPos )))
1738     {
1739         rPackageName.SetChar( nPos, '_' );
1740         ++nPos;
1741     }
1742 }
1743 
DecryptBlockName_Imp(String & rName)1744 void DecryptBlockName_Imp( String& rName )
1745 {
1746     if( '#' == rName.GetChar( 0 ) )
1747     {
1748         rName.Erase( 0, 1 );
1749         sal_Unicode* pName = rName.GetBufferAccess();
1750         xub_StrLen nLen, nPos;
1751         for ( nLen = rName.Len(), nPos = 0; nPos < nLen; ++nPos, ++pName )
1752             switch( *pName )
1753             {
1754             case 0x01:  *pName = '!';   break;
1755             case 0x0A:  *pName = ':';   break;
1756             case 0x0C:  *pName = '\\';  break;
1757             case 0x0E:  *pName = '.';   break;
1758             case 0x0F:  *pName = '/';   break;
1759             }
1760     }
1761 }
1762 
1763 
1764 /* -----------------18.11.98 16:00-------------------
1765  *
1766  * --------------------------------------------------*/
lcl_SearchWordsInList(SvxAutoCorrectLanguageListsPtr pList,const String & rTxt,xub_StrLen & rStt,xub_StrLen nEndPos,SvxAutoCorrDoc &)1767 const SvxAutocorrWord* lcl_SearchWordsInList(
1768                 SvxAutoCorrectLanguageListsPtr pList, const String& rTxt,
1769                 xub_StrLen& rStt, xub_StrLen nEndPos, SvxAutoCorrDoc& )
1770 {
1771     const SvxAutocorrWordList* pAutoCorrWordList = pList->GetAutocorrWordList();
1772     TransliterationWrapper& rCmp = GetIgnoreTranslWrapper();
1773     for( xub_StrLen nPos = 0; nPos < pAutoCorrWordList->Count(); ++nPos )
1774     {
1775         const SvxAutocorrWord* pFnd = (*pAutoCorrWordList)[ nPos ];
1776         const String& rChk = pFnd->GetShort();
1777         if( nEndPos >= rChk.Len() )
1778         {
1779             xub_StrLen nCalcStt = nEndPos - rChk.Len();
1780             if( ( !nCalcStt || nCalcStt == rStt ||
1781                 ( nCalcStt < rStt &&
1782                     IsWordDelim( rTxt.GetChar(nCalcStt - 1 ) ))) )
1783             {
1784                 String sWord( rTxt.GetBuffer() + nCalcStt, rChk.Len() );
1785                 if( rCmp.isEqual( rChk, sWord ))
1786                 {
1787                     rStt = nCalcStt;
1788                     return pFnd;
1789                 }
1790             }
1791         }
1792     }
1793     return 0;
1794 }
1795 
1796 
1797 // suche das oder die Worte in der ErsetzungsTabelle
SearchWordsInList(const String & rTxt,xub_StrLen & rStt,xub_StrLen nEndPos,SvxAutoCorrDoc & rDoc,LanguageType & rLang)1798 const SvxAutocorrWord* SvxAutoCorrect::SearchWordsInList(
1799                 const String& rTxt, xub_StrLen& rStt, xub_StrLen nEndPos,
1800                 SvxAutoCorrDoc& rDoc, LanguageType& rLang )
1801 {
1802     LanguageType eLang = rLang;
1803     const SvxAutocorrWord* pRet = 0;
1804     if( LANGUAGE_SYSTEM == eLang )
1805         eLang = MsLangId::getSystemLanguage();
1806 
1807     // zuerst nach eLang suchen, dann nach der Obersprache
1808     // US-Englisch -> Englisch und zuletzt in LANGUAGE_DONTKNOW
1809 
1810     if( pLangTable->IsKeyValid( sal_uLong( eLang ) ) ||
1811         CreateLanguageFile( eLang, sal_False ))
1812     {
1813         //die Sprache ist vorhanden - also her damit
1814         SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(sal_uLong(eLang));
1815         pRet = lcl_SearchWordsInList(  pList, rTxt, rStt, nEndPos, rDoc );
1816         if( pRet )
1817         {
1818             rLang = eLang;
1819             return pRet;
1820         }
1821     }
1822 
1823     // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen
1824     sal_uLong nTmpKey1 = eLang & 0x7ff, // die Hauptsprache in vielen Faellen u.B. DE
1825           nTmpKey2 = eLang & 0x3ff, // sonst z.B. EN
1826           nTmp;
1827 
1828     if( ((nTmp = nTmpKey1) != (sal_uLong)eLang &&
1829          ( pLangTable->IsKeyValid( nTmpKey1 ) ||
1830            CreateLanguageFile( LanguageType( nTmpKey1 ), sal_False ) )) ||
1831         (( nTmp = nTmpKey2) != (sal_uLong)eLang &&
1832          ( pLangTable->IsKeyValid( nTmpKey2 ) ||
1833            CreateLanguageFile( LanguageType( nTmpKey2 ), sal_False ) )) )
1834     {
1835         //die Sprache ist vorhanden - also her damit
1836         SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek( nTmp );
1837         pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc);
1838         if( pRet )
1839         {
1840             rLang = LanguageType( nTmp );
1841             return pRet;
1842         }
1843     }
1844     if( pLangTable->IsKeyValid( sal_uLong( LANGUAGE_DONTKNOW ) ) ||
1845         CreateLanguageFile( LANGUAGE_DONTKNOW, sal_False ) )
1846     {
1847         //die Sprache ist vorhanden - also her damit
1848         SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(sal_uLong(LANGUAGE_DONTKNOW));
1849         pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc);
1850         if( pRet )
1851         {
1852             rLang = LANGUAGE_DONTKNOW;
1853             return pRet;
1854         }
1855     }
1856     return 0;
1857 }
1858 /* -----------------18.11.98 13:46-------------------
1859  *
1860  * --------------------------------------------------*/
FindInWrdSttExceptList(LanguageType eLang,const String & sWord)1861 sal_Bool SvxAutoCorrect::FindInWrdSttExceptList( LanguageType eLang,
1862                                              const String& sWord )
1863 {
1864     //zuerst nach eLang suchen, dann nach der Obersprace US-Englisch -> Englisch
1865     //und zuletzt in LANGUAGE_DONTKNOW
1866     sal_uLong nTmpKey1 = eLang & 0x7ff; // die Hauptsprache in vielen Faellen u.B. DE
1867     sal_uLong nTmpKey2 = eLang & 0x3ff; // sonst z.B. EN
1868     String sTemp(sWord);
1869     if( pLangTable->IsKeyValid( sal_uLong( eLang )) ||
1870         CreateLanguageFile( eLang, sal_False ) )
1871     {
1872         //die Sprache ist vorhanden - also her damit
1873         SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(sal_uLong(eLang));
1874         String _sTemp(sWord);
1875         if(pList->GetWrdSttExceptList()->Seek_Entry(&_sTemp))
1876             return sal_True;
1877 
1878     }
1879     // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen
1880     sal_uLong nTmp;
1881     if( ((nTmp = nTmpKey1) != (sal_uLong)eLang &&
1882          ( pLangTable->IsKeyValid( nTmpKey1 ) ||
1883            CreateLanguageFile( LanguageType( nTmpKey1 ), sal_False ) )) ||
1884         (( nTmp = nTmpKey2) != (sal_uLong)eLang &&
1885          ( pLangTable->IsKeyValid( nTmpKey2 ) ||
1886            CreateLanguageFile( LanguageType( nTmpKey2 ), sal_False ) )) )
1887     {
1888         //die Sprache ist vorhanden - also her damit
1889         SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(nTmp);
1890         if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp))
1891             return sal_True;
1892     }
1893     if(pLangTable->IsKeyValid(sal_uLong(LANGUAGE_DONTKNOW))|| CreateLanguageFile(LANGUAGE_DONTKNOW, sal_False))
1894     {
1895         //die Sprache ist vorhanden - also her damit
1896         SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(sal_uLong(LANGUAGE_DONTKNOW));
1897         if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp))
1898             return sal_True;
1899     }
1900     return sal_False;
1901 }
1902 /* -----------------18.11.98 14:28-------------------
1903  *
1904  * --------------------------------------------------*/
lcl_FindAbbreviation(const SvStringsISortDtor * pList,const String & sWord)1905 sal_Bool lcl_FindAbbreviation( const SvStringsISortDtor* pList, const String& sWord)
1906 {
1907     String sAbk( '~' );
1908     sal_uInt16 nPos;
1909     pList->Seek_Entry( &sAbk, &nPos );
1910     if( nPos < pList->Count() )
1911     {
1912         String sLowerWord( sWord ); sLowerWord.ToLowerAscii();
1913         const String* pAbk;
1914         for( sal_uInt16 n = nPos;
1915                 n < pList->Count() &&
1916                 '~' == ( pAbk = (*pList)[ n ])->GetChar( 0 );
1917             ++n )
1918         {
1919             // ~ und ~. sind nicht erlaubt!
1920             if( 2 < pAbk->Len() && pAbk->Len() - 1 <= sWord.Len() )
1921             {
1922                 String sLowerAbk( *pAbk ); sLowerAbk.ToLowerAscii();
1923                 for( xub_StrLen i = sLowerAbk.Len(), ii = sLowerWord.Len(); i; )
1924                 {
1925                     if( !--i )      // stimmt ueberein
1926                         return sal_True;
1927 
1928                     if( sLowerAbk.GetChar( i ) != sLowerWord.GetChar( --ii ))
1929                         break;
1930                 }
1931             }
1932         }
1933     }
1934     DBG_ASSERT( !(nPos && '~' == (*pList)[ --nPos ]->GetChar( 0 ) ),
1935             "falsch sortierte ExeptionListe?" );
1936     return sal_False;
1937 }
1938 /* -----------------18.11.98 14:49-------------------
1939  *
1940  * --------------------------------------------------*/
FindInCplSttExceptList(LanguageType eLang,const String & sWord,sal_Bool bAbbreviation)1941 sal_Bool SvxAutoCorrect::FindInCplSttExceptList(LanguageType eLang,
1942                                 const String& sWord, sal_Bool bAbbreviation)
1943 {
1944     //zuerst nach eLang suchen, dann nach der Obersprace US-Englisch -> Englisch
1945     //und zuletzt in LANGUAGE_DONTKNOW
1946     sal_uLong nTmpKey1 = eLang & 0x7ff; // die Hauptsprache in vielen Faellen u.B. DE
1947     sal_uLong nTmpKey2 = eLang & 0x3ff; // sonst z.B. EN
1948     String sTemp( sWord );
1949     if( pLangTable->IsKeyValid( sal_uLong( eLang )) ||
1950         CreateLanguageFile( eLang, sal_False ))
1951     {
1952         //die Sprache ist vorhanden - also her damit
1953         SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(sal_uLong(eLang));
1954         const SvStringsISortDtor* pList = pLists->GetCplSttExceptList();
1955         if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord)
1956                          : pList->Seek_Entry( &sTemp ) )
1957             return sal_True;
1958     }
1959     // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen
1960     sal_uLong nTmp;
1961 
1962     if( ((nTmp = nTmpKey1) != (sal_uLong)eLang &&
1963          ( pLangTable->IsKeyValid( nTmpKey1 ) ||
1964            CreateLanguageFile( LanguageType( nTmpKey1 ), sal_False ) )) ||
1965         (( nTmp = nTmpKey2) != (sal_uLong)eLang &&
1966          ( pLangTable->IsKeyValid( nTmpKey2 ) ||
1967            CreateLanguageFile( LanguageType( nTmpKey2 ), sal_False ) )) )
1968     {
1969         //die Sprache ist vorhanden - also her damit
1970         SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(nTmp);
1971         const SvStringsISortDtor* pList = pLists->GetCplSttExceptList();
1972         if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord)
1973                          : pList->Seek_Entry( &sTemp ) )
1974             return sal_True;
1975     }
1976     if(pLangTable->IsKeyValid(sal_uLong(LANGUAGE_DONTKNOW))|| CreateLanguageFile(LANGUAGE_DONTKNOW, sal_False))
1977     {
1978         //die Sprache ist vorhanden - also her damit
1979         SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(LANGUAGE_DONTKNOW);
1980         const SvStringsISortDtor* pList = pLists->GetCplSttExceptList();
1981         if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord)
1982                          : pList->Seek_Entry( &sTemp ) )
1983             return sal_True;
1984     }
1985     return sal_False;
1986 
1987 }
1988 
1989 /* -----------------20.11.98 11:53-------------------
1990  *
1991  * --------------------------------------------------*/
GetAutoCorrFileName(LanguageType eLang,sal_Bool bNewFile,sal_Bool bTst) const1992 String SvxAutoCorrect::GetAutoCorrFileName( LanguageType eLang,
1993                                             sal_Bool bNewFile, sal_Bool bTst ) const
1994 {
1995     String sRet, sExt( MsLangId::convertLanguageToIsoString( eLang ) );
1996     sExt.Insert('_', 0);
1997     sExt.AppendAscii( ".dat" );
1998     if( bNewFile )
1999         ( sRet = sUserAutoCorrFile )  += sExt;
2000     else if( !bTst )
2001         ( sRet = sShareAutoCorrFile )  += sExt;
2002     else
2003     {
2004         // test first in the user directory - if not exist, then
2005         ( sRet = sUserAutoCorrFile ) += sExt;
2006         if( !FStatHelper::IsDocument( sRet ))
2007             ( sRet = sShareAutoCorrFile ) += sExt;
2008     }
2009     return sRet;
2010 }
2011 
2012 /* -----------------18.11.98 11:16-------------------
2013  *
2014  * --------------------------------------------------*/
SvxAutoCorrectLanguageLists(SvxAutoCorrect & rParent,const String & rShareAutoCorrectFile,const String & rUserAutoCorrectFile,LanguageType eLang)2015 SvxAutoCorrectLanguageLists::SvxAutoCorrectLanguageLists(
2016                 SvxAutoCorrect& rParent,
2017                 const String& rShareAutoCorrectFile,
2018                 const String& rUserAutoCorrectFile,
2019                 LanguageType eLang)
2020 :   sShareAutoCorrFile( rShareAutoCorrectFile ),
2021     sUserAutoCorrFile( rUserAutoCorrectFile ),
2022     eLanguage(eLang),
2023     pCplStt_ExcptLst( 0 ),
2024     pWrdStt_ExcptLst( 0 ),
2025     pAutocorr_List( 0 ),
2026     rAutoCorrect(rParent),
2027     nFlags(0)
2028 {
2029 }
2030 
2031 /* -----------------18.11.98 11:16-------------------
2032  *
2033  * --------------------------------------------------*/
~SvxAutoCorrectLanguageLists()2034 SvxAutoCorrectLanguageLists::~SvxAutoCorrectLanguageLists()
2035 {
2036     delete pCplStt_ExcptLst;
2037     delete pWrdStt_ExcptLst;
2038     delete pAutocorr_List;
2039 }
2040 
2041 /* -----------------18.11.98 11:26-------------------
2042  *
2043  * --------------------------------------------------*/
IsFileChanged_Imp()2044 sal_Bool SvxAutoCorrectLanguageLists::IsFileChanged_Imp()
2045 {
2046     // nur alle 2 Minuten aufs FileSystem zugreifen um den
2047     // Dateistempel zu ueberpruefen
2048     sal_Bool bRet = sal_False;
2049 
2050     Time nMinTime( 0, 2 );
2051     Time nAktTime;
2052     if( aLastCheckTime > nAktTime ||                    // ueberlauf ?
2053         ( nAktTime -= aLastCheckTime ) > nMinTime )     // min Zeit vergangen
2054     {
2055         Date aTstDate; Time aTstTime;
2056         if( FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
2057                                             &aTstDate, &aTstTime ) &&
2058             ( aModifiedDate != aTstDate || aModifiedTime != aTstTime ))
2059         {
2060             bRet = sal_True;
2061             // dann mal schnell alle Listen entfernen!
2062             if( CplSttLstLoad & nFlags && pCplStt_ExcptLst )
2063                 delete pCplStt_ExcptLst, pCplStt_ExcptLst = 0;
2064             if( WrdSttLstLoad & nFlags && pWrdStt_ExcptLst )
2065                 delete pWrdStt_ExcptLst, pWrdStt_ExcptLst = 0;
2066             if( ChgWordLstLoad & nFlags && pAutocorr_List )
2067                 delete pAutocorr_List, pAutocorr_List = 0;
2068             nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad );
2069         }
2070         aLastCheckTime = Time();
2071     }
2072     return bRet;
2073 }
2074 
LoadXMLExceptList_Imp(SvStringsISortDtor * & rpLst,const sal_Char * pStrmName,SotStorageRef & rStg)2075 void SvxAutoCorrectLanguageLists::LoadXMLExceptList_Imp(
2076                                         SvStringsISortDtor*& rpLst,
2077                                         const sal_Char* pStrmName,
2078                                         SotStorageRef& rStg)
2079 {
2080     if( rpLst )
2081         rpLst->DeleteAndDestroy( 0, rpLst->Count() );
2082     else
2083         rpLst = new SvStringsISortDtor( 16, 16 );
2084 
2085     {
2086         String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 );
2087         String sTmp( sStrmName );
2088 
2089         if( rStg.Is() && rStg->IsStream( sStrmName ) )
2090         {
2091             SvStorageStreamRef xStrm = rStg->OpenSotStream( sTmp,
2092                 ( STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE ) );
2093             if( SVSTREAM_OK != xStrm->GetError())
2094             {
2095                 xStrm.Clear();
2096                 rStg.Clear();
2097                 RemoveStream_Imp( sStrmName );
2098             }
2099             else
2100             {
2101                 uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2102                     comphelper::getProcessServiceFactory();
2103                 DBG_ASSERT( xServiceFactory.is(),
2104                     "XMLReader::Read: got no service manager" );
2105                 if( !xServiceFactory.is() )
2106                 {
2107                     // Throw an exception ?
2108                 }
2109 
2110                 xml::sax::InputSource aParserInput;
2111                 aParserInput.sSystemId = sStrmName;
2112 
2113                 xStrm->Seek( 0L );
2114                 xStrm->SetBufferSize( 8 * 1024 );
2115                 aParserInput.aInputStream = new utl::OInputStreamWrapper( *xStrm );
2116 
2117                 // get parser
2118                 uno::Reference< XInterface > xXMLParser = xServiceFactory->createInstance(
2119                     OUString::createFromAscii("com.sun.star.xml.sax.Parser") );
2120                 DBG_ASSERT( xXMLParser.is(),
2121                     "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" );
2122                 if( !xXMLParser.is() )
2123                 {
2124                     // Maybe throw an exception?
2125                 }
2126 
2127                 // get filter
2128                 // #110680#
2129                 // uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLExceptionListImport ( *rpLst );
2130                 uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLExceptionListImport ( xServiceFactory, *rpLst );
2131 
2132                 // connect parser and filter
2133                 uno::Reference< xml::sax::XParser > xParser( xXMLParser, UNO_QUERY );
2134                 xParser->setDocumentHandler( xFilter );
2135 
2136                 // parse
2137                 try
2138                 {
2139                     xParser->parseStream( aParserInput );
2140                 }
2141                 catch( xml::sax::SAXParseException&  )
2142                 {
2143                     // re throw ?
2144                 }
2145                 catch( xml::sax::SAXException&  )
2146                 {
2147                     // re throw ?
2148                 }
2149                 catch( io::IOException& )
2150                 {
2151                     // re throw ?
2152                 }
2153             }
2154         }
2155 
2156         // Zeitstempel noch setzen
2157         FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
2158                                         &aModifiedDate, &aModifiedTime );
2159         aLastCheckTime = Time();
2160     }
2161 
2162 }
2163 /* -----------------18.11.98 11:26-------------------
2164  *
2165  * --------------------------------------------------*/
SaveExceptList_Imp(const SvStringsISortDtor & rLst,const sal_Char * pStrmName,SotStorageRef & rStg,sal_Bool bConvert)2166 void SvxAutoCorrectLanguageLists::SaveExceptList_Imp(
2167                             const SvStringsISortDtor& rLst,
2168                             const sal_Char* pStrmName,
2169                             SotStorageRef &rStg,
2170                             sal_Bool bConvert )
2171 {
2172     if( rStg.Is() )
2173     {
2174         String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 );
2175         if( !rLst.Count() )
2176         {
2177             rStg->Remove( sStrmName );
2178             rStg->Commit();
2179         }
2180         else
2181         {
2182             SotStorageStreamRef xStrm = rStg->OpenSotStream( sStrmName,
2183                     ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) );
2184             if( xStrm.Is() )
2185             {
2186                 xStrm->SetSize( 0 );
2187                 xStrm->SetBufferSize( 8192 );
2188                 String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
2189                 OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") );
2190                 uno::Any aAny;
2191                 aAny <<= aMime;
2192                 xStrm->SetProperty( aPropName, aAny );
2193 
2194 
2195                 uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2196                     comphelper::getProcessServiceFactory();
2197                 DBG_ASSERT( xServiceFactory.is(),
2198                             "XMLReader::Read: got no service manager" );
2199                 if( !xServiceFactory.is() )
2200                 {
2201                     // Throw an exception ?
2202                 }
2203 
2204                 uno::Reference < XInterface > xWriter (xServiceFactory->createInstance(
2205                      OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer"))));
2206                 DBG_ASSERT(xWriter.is(),"com.sun.star.xml.sax.Writer service missing");
2207                 uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *xStrm );
2208                 uno::Reference<io::XActiveDataSource> xSrc(xWriter, uno::UNO_QUERY);
2209                 xSrc->setOutputStream(xOut);
2210 
2211                 uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY);
2212 
2213                 // #110680#
2214                 // SvXMLExceptionListExport aExp(rLst, sStrmName, xHandler);
2215                 SvXMLExceptionListExport aExp( xServiceFactory, rLst, sStrmName, xHandler );
2216 
2217                 aExp.exportDoc( XML_BLOCK_LIST );
2218 
2219                 xStrm->Commit();
2220                 if( xStrm->GetError() == SVSTREAM_OK )
2221                 {
2222                     xStrm.Clear();
2223                     if (!bConvert)
2224                     {
2225                         rStg->Commit();
2226                         if( SVSTREAM_OK != rStg->GetError() )
2227                         {
2228                             rStg->Remove( sStrmName );
2229                             rStg->Commit();
2230                         }
2231                     }
2232                 }
2233             }
2234         }
2235     }
2236 }
2237 /* -----------------18.11.98 11:26-------------------
2238  *
2239  * --------------------------------------------------*/
LoadAutocorrWordList()2240 SvxAutocorrWordList* SvxAutoCorrectLanguageLists::LoadAutocorrWordList()
2241 {
2242     if( pAutocorr_List )
2243         pAutocorr_List->DeleteAndDestroy( 0, pAutocorr_List->Count() );
2244     else
2245         pAutocorr_List = new SvxAutocorrWordList( 16, 16 );
2246 
2247     SvStringsDtor aRemoveArr;
2248     try
2249     {
2250         uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sShareAutoCorrFile, embed::ElementModes::READ );
2251         String aXMLWordListName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 );
2252         uno::Reference < io::XStream > xStrm = xStg->openStreamElement( aXMLWordListName, embed::ElementModes::READ );
2253         uno::Reference< lang::XMultiServiceFactory > xServiceFactory = comphelper::getProcessServiceFactory();
2254 
2255         xml::sax::InputSource aParserInput;
2256         aParserInput.sSystemId = aXMLWordListName;
2257         aParserInput.aInputStream = xStrm->getInputStream();
2258 
2259         // get parser
2260         uno::Reference< XInterface > xXMLParser = xServiceFactory->createInstance( OUString::createFromAscii("com.sun.star.xml.sax.Parser") );
2261         DBG_ASSERT( xXMLParser.is(), "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" );
2262         if( xXMLParser.is() )
2263         {
2264             uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLAutoCorrectImport( xServiceFactory, pAutocorr_List, rAutoCorrect, xStg );
2265 
2266             // connect parser and filter
2267             uno::Reference< xml::sax::XParser > xParser( xXMLParser, UNO_QUERY );
2268             xParser->setDocumentHandler( xFilter );
2269 
2270             // parse
2271             xParser->parseStream( aParserInput );
2272         }
2273     }
2274     catch ( uno::Exception& )
2275     {
2276     }
2277 
2278     // Zeitstempel noch setzen
2279     FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
2280                                     &aModifiedDate, &aModifiedTime );
2281     aLastCheckTime = Time();
2282 
2283     return pAutocorr_List;
2284 }
2285 
2286 /* -----------------18.11.98 11:26-------------------
2287  *
2288  * --------------------------------------------------*/
2289 
SetAutocorrWordList(SvxAutocorrWordList * pList)2290 void SvxAutoCorrectLanguageLists::SetAutocorrWordList( SvxAutocorrWordList* pList )
2291 {
2292     if( pAutocorr_List && pList != pAutocorr_List )
2293         delete pAutocorr_List;
2294     pAutocorr_List = pList;
2295     if( !pAutocorr_List )
2296     {
2297         DBG_ASSERT( !this, "keine gueltige Liste" );
2298         pAutocorr_List = new SvxAutocorrWordList( 16, 16 );
2299     }
2300     nFlags |= ChgWordLstLoad;
2301 }
2302 
2303 /* -----------------18.11.98 11:26-------------------
2304  *
2305  * --------------------------------------------------*/
GetAutocorrWordList()2306 const SvxAutocorrWordList* SvxAutoCorrectLanguageLists::GetAutocorrWordList()
2307 {
2308     if( !( ChgWordLstLoad & nFlags ) || IsFileChanged_Imp() )
2309         SetAutocorrWordList( LoadAutocorrWordList() );
2310     return pAutocorr_List;
2311 }
2312 /* -----------------18.11.98 11:26-------------------
2313  *
2314  * --------------------------------------------------*/
GetCplSttExceptList()2315 SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetCplSttExceptList()
2316 {
2317     if( !( CplSttLstLoad & nFlags ) || IsFileChanged_Imp() )
2318         SetCplSttExceptList( LoadCplSttExceptList() );
2319     return pCplStt_ExcptLst;
2320 }
2321 /* -----------------18.11.98 11:26-------------------
2322  *
2323  * --------------------------------------------------*/
AddToCplSttExceptList(const String & rNew)2324 sal_Bool SvxAutoCorrectLanguageLists::AddToCplSttExceptList(const String& rNew)
2325 {
2326     String* pNew = new String( rNew );
2327     if( rNew.Len() && GetCplSttExceptList()->Insert( pNew ) )
2328     {
2329         MakeUserStorage_Impl();
2330         SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2331 
2332         SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2333 
2334         xStg = 0;
2335         // Zeitstempel noch setzen
2336         FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2337                                             &aModifiedDate, &aModifiedTime );
2338         aLastCheckTime = Time();
2339     }
2340     else
2341         delete pNew, pNew = 0;
2342     return 0 != pNew;
2343 }
2344 /* -----------------18.11.98 15:20-------------------
2345  *
2346  * --------------------------------------------------*/
AddToWrdSttExceptList(const String & rNew)2347 sal_Bool SvxAutoCorrectLanguageLists::AddToWrdSttExceptList(const String& rNew)
2348 {
2349     String* pNew = new String( rNew );
2350     SvStringsISortDtor* pExceptList = LoadWrdSttExceptList();
2351     if( rNew.Len() && pExceptList && pExceptList->Insert( pNew ) )
2352     {
2353         MakeUserStorage_Impl();
2354         SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2355 
2356         SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2357 
2358         xStg = 0;
2359         // Zeitstempel noch setzen
2360         FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2361                                             &aModifiedDate, &aModifiedTime );
2362         aLastCheckTime = Time();
2363     }
2364     else
2365         delete pNew, pNew = 0;
2366     return 0 != pNew;
2367 }
2368 
2369 /* -----------------18.11.98 11:26-------------------
2370  *
2371  * --------------------------------------------------*/
LoadCplSttExceptList()2372 SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadCplSttExceptList()
2373 {
2374     SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, sal_True );
2375     String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) );
2376     if( xStg.Is() && xStg->IsContained( sTemp ) )
2377         LoadXMLExceptList_Imp( pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2378 
2379     return pCplStt_ExcptLst;
2380 }
2381 
2382 /* -----------------18.11.98 11:26-------------------
2383  *
2384  * --------------------------------------------------*/
SaveCplSttExceptList()2385 void SvxAutoCorrectLanguageLists::SaveCplSttExceptList()
2386 {
2387     MakeUserStorage_Impl();
2388     SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2389 
2390     SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2391 
2392     xStg = 0;
2393 
2394     // Zeitstempel noch setzen
2395     FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2396                                             &aModifiedDate, &aModifiedTime );
2397     aLastCheckTime = Time();
2398 }
2399 
2400 /* -----------------18.11.98 11:26-------------------
2401  *
2402  * --------------------------------------------------*/
SetCplSttExceptList(SvStringsISortDtor * pList)2403 void SvxAutoCorrectLanguageLists::SetCplSttExceptList( SvStringsISortDtor* pList )
2404 {
2405     if( pCplStt_ExcptLst && pList != pCplStt_ExcptLst )
2406         delete pCplStt_ExcptLst;
2407 
2408     pCplStt_ExcptLst = pList;
2409     if( !pCplStt_ExcptLst )
2410     {
2411         DBG_ASSERT( !this, "keine gueltige Liste" );
2412         pCplStt_ExcptLst = new SvStringsISortDtor( 16, 16 );
2413     }
2414     nFlags |= CplSttLstLoad;
2415 }
2416 /* -----------------18.11.98 11:26-------------------
2417  *
2418  * --------------------------------------------------*/
LoadWrdSttExceptList()2419 SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadWrdSttExceptList()
2420 {
2421     SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, sal_True );
2422     String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) );
2423     if( xStg.Is() && xStg->IsContained( sTemp ) )
2424         LoadXMLExceptList_Imp( pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2425     return pWrdStt_ExcptLst;
2426 }
2427 /* -----------------18.11.98 11:26-------------------
2428  *
2429  * --------------------------------------------------*/
SaveWrdSttExceptList()2430 void SvxAutoCorrectLanguageLists::SaveWrdSttExceptList()
2431 {
2432     MakeUserStorage_Impl();
2433     SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2434 
2435     SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2436 
2437     xStg = 0;
2438     // Zeitstempel noch setzen
2439     FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2440                                             &aModifiedDate, &aModifiedTime );
2441     aLastCheckTime = Time();
2442 }
2443 /* -----------------18.11.98 11:26-------------------
2444  *
2445  * --------------------------------------------------*/
SetWrdSttExceptList(SvStringsISortDtor * pList)2446 void SvxAutoCorrectLanguageLists::SetWrdSttExceptList( SvStringsISortDtor* pList )
2447 {
2448     if( pWrdStt_ExcptLst && pList != pWrdStt_ExcptLst )
2449         delete pWrdStt_ExcptLst;
2450     pWrdStt_ExcptLst = pList;
2451     if( !pWrdStt_ExcptLst )
2452     {
2453         DBG_ASSERT( !this, "keine gueltige Liste" );
2454         pWrdStt_ExcptLst = new SvStringsISortDtor( 16, 16 );
2455     }
2456     nFlags |= WrdSttLstLoad;
2457 }
2458 /* -----------------18.11.98 11:26-------------------
2459  *
2460  * --------------------------------------------------*/
GetWrdSttExceptList()2461 SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetWrdSttExceptList()
2462 {
2463     if( !( WrdSttLstLoad & nFlags ) || IsFileChanged_Imp() )
2464         SetWrdSttExceptList( LoadWrdSttExceptList() );
2465     return pWrdStt_ExcptLst;
2466 }
2467 /* -----------------18.11.98 11:26-------------------
2468  *
2469  * --------------------------------------------------*/
RemoveStream_Imp(const String & rName)2470 void SvxAutoCorrectLanguageLists::RemoveStream_Imp( const String& rName )
2471 {
2472     if( sShareAutoCorrFile != sUserAutoCorrFile )
2473     {
2474         SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2475         if( xStg.Is() && SVSTREAM_OK == xStg->GetError() &&
2476             xStg->IsStream( rName ) )
2477         {
2478             xStg->Remove( rName );
2479             xStg->Commit();
2480 
2481             xStg = 0;
2482         }
2483     }
2484 }
2485 
MakeUserStorage_Impl()2486 void SvxAutoCorrectLanguageLists::MakeUserStorage_Impl()
2487 {
2488     // The conversion needs to happen if the file is already in the user
2489     // directory and is in the old format. Additionally it needs to
2490     // happen when the file is being copied from share to user.
2491 
2492     sal_Bool bError = sal_False, bConvert = sal_False, bCopy = sal_False;
2493     INetURLObject aDest;
2494     INetURLObject aSource;
2495 
2496 //  String sDestPath = sUserAutoCorrFile.Copy ( 0, sUserAutoCorrFile.Len()-3);
2497 //  sDestPath.AppendAscii ("bak");
2498 
2499 
2500     if (sUserAutoCorrFile != sShareAutoCorrFile )
2501     {
2502         aSource = INetURLObject ( sShareAutoCorrFile ); //aSource.setFSysPath ( sShareAutoCorrFile, INetURLObject::FSYS_DETECT );
2503         aDest = INetURLObject ( sUserAutoCorrFile );
2504         if ( SotStorage::IsOLEStorage ( sShareAutoCorrFile ) )
2505         {
2506             aDest.SetExtension ( String::CreateFromAscii ( "bak" ) );
2507             bConvert = sal_True;
2508         }
2509         bCopy = sal_True;
2510     }
2511     else if ( SotStorage::IsOLEStorage ( sUserAutoCorrFile ) )
2512     {
2513         aSource = INetURLObject ( sUserAutoCorrFile );
2514         aDest = INetURLObject ( sUserAutoCorrFile );
2515         aDest.SetExtension ( String::CreateFromAscii ( "bak" ) );
2516         bCopy = bConvert = sal_True;
2517     }
2518     if (bCopy)
2519     {
2520         try
2521         {
2522             String sMain(aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ));
2523             sal_Unicode cSlash = '/';
2524             xub_StrLen nSlashPos = sMain.SearchBackward(cSlash);
2525             sMain.Erase(nSlashPos);
2526             ::ucbhelper::Content aNewContent(   sMain, uno::Reference< XCommandEnvironment > ());
2527             Any aAny;
2528             TransferInfo aInfo;
2529             aInfo.NameClash = NameClash::OVERWRITE;
2530             aInfo.NewTitle  = aDest.GetName();
2531             aInfo.SourceURL = aSource.GetMainURL( INetURLObject::DECODE_TO_IURI );
2532             aInfo.MoveData  = sal_False;
2533             aAny <<= aInfo;
2534             aNewContent.executeCommand( OUString ( RTL_CONSTASCII_USTRINGPARAM( "transfer" ) ), aAny);
2535         }
2536         catch (...)
2537         {
2538             bError = sal_True;
2539         }
2540     }
2541     if (bConvert && !bError)
2542     {
2543         SotStorageRef xSrcStg = new SotStorage( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), STREAM_READ, sal_True );
2544         SotStorageRef xDstStg = new SotStorage( sUserAutoCorrFile, STREAM_WRITE, sal_True );
2545 
2546         if( xSrcStg.Is() && xDstStg.Is() )
2547         {
2548             String sWord        ( RTL_CONSTASCII_USTRINGPARAM ( pImplWrdStt_ExcptLstStr ) );
2549             String sSentence    ( RTL_CONSTASCII_USTRINGPARAM ( pImplCplStt_ExcptLstStr ) );
2550             String sXMLWord     ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) );
2551             String sXMLSentence ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) );
2552             SvStringsISortDtor  *pTmpWordList = NULL;
2553 
2554             if (xSrcStg->IsContained( sXMLWord ) )
2555                 LoadXMLExceptList_Imp( pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xSrcStg );
2556 
2557             if (pTmpWordList)
2558             {
2559                 SaveExceptList_Imp( *pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xDstStg, sal_True );
2560                 pTmpWordList->DeleteAndDestroy( 0, pTmpWordList->Count() );
2561                 pTmpWordList = NULL;
2562             }
2563 
2564 
2565             if (xSrcStg->IsContained( sXMLSentence ) )
2566                 LoadXMLExceptList_Imp( pTmpWordList, pXMLImplCplStt_ExcptLstStr, xSrcStg );
2567 
2568             if (pTmpWordList)
2569             {
2570                 SaveExceptList_Imp( *pTmpWordList, pXMLImplCplStt_ExcptLstStr, xDstStg, sal_True );
2571                 pTmpWordList->DeleteAndDestroy( 0, pTmpWordList->Count() );
2572             }
2573 
2574             GetAutocorrWordList();
2575             MakeBlocklist_Imp( *xDstStg );
2576             // xDstStg is committed in MakeBlocklist_Imp
2577             /*xSrcStg->CopyTo( &xDstStg );*/
2578             sShareAutoCorrFile = sUserAutoCorrFile;
2579             xDstStg = 0;
2580             try
2581             {
2582                 ::ucbhelper::Content aContent ( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), uno::Reference < XCommandEnvironment > ());
2583                 aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "delete" ) ), makeAny ( sal_Bool (sal_True ) ) );
2584             }
2585             catch (...)
2586             {
2587             }
2588         }
2589     }
2590     else if( bCopy && !bError )
2591         sShareAutoCorrFile = sUserAutoCorrFile;
2592 }
2593 
2594 /* -----------------18.11.98 11:26-------------------
2595  *
2596  * --------------------------------------------------*/
MakeBlocklist_Imp(SvStorage & rStg)2597 sal_Bool SvxAutoCorrectLanguageLists::MakeBlocklist_Imp( SvStorage& rStg )
2598 {
2599     String sStrmName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 );
2600     sal_Bool bRet = sal_True, bRemove = !pAutocorr_List || !pAutocorr_List->Count();
2601     if( !bRemove )
2602     {
2603         /*
2604         if ( rStg.IsContained( sStrmName) )
2605         {
2606             rStg.Remove ( sStrmName );
2607             rStg.Commit();
2608         }
2609         */
2610         SvStorageStreamRef refList = rStg.OpenSotStream( sStrmName,
2611                     ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) );
2612         if( refList.Is() )
2613         {
2614             refList->SetSize( 0 );
2615             refList->SetBufferSize( 8192 );
2616             String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
2617             OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") );
2618             uno::Any aAny;
2619             aAny <<= aMime;
2620             refList->SetProperty( aPropName, aAny );
2621 
2622             uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2623                 comphelper::getProcessServiceFactory();
2624             DBG_ASSERT( xServiceFactory.is(),
2625                         "XMLReader::Read: got no service manager" );
2626             if( !xServiceFactory.is() )
2627             {
2628                 // Throw an exception ?
2629             }
2630 
2631             uno::Reference < XInterface > xWriter (xServiceFactory->createInstance(
2632                  OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer"))));
2633             DBG_ASSERT(xWriter.is(),"com.sun.star.xml.sax.Writer service missing");
2634             uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *refList );
2635             uno::Reference<io::XActiveDataSource> xSrc(xWriter, uno::UNO_QUERY);
2636             xSrc->setOutputStream(xOut);
2637 
2638             uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY);
2639 
2640             // #110680#
2641             // SvXMLAutoCorrectExport aExp(pAutocorr_List, sStrmName, xHandler);
2642             SvXMLAutoCorrectExport aExp( xServiceFactory, pAutocorr_List, sStrmName, xHandler );
2643 
2644             aExp.exportDoc( XML_BLOCK_LIST );
2645 
2646             refList->Commit();
2647             bRet = SVSTREAM_OK == refList->GetError();
2648             if( bRet )
2649             {
2650                 refList.Clear();
2651                 rStg.Commit();
2652                 if( SVSTREAM_OK != rStg.GetError() )
2653                 {
2654                     bRemove = sal_True;
2655                     bRet = sal_False;
2656                 }
2657             }
2658 
2659             /*
2660             refList->SetSize( 0 );
2661             refList->SetBufferSize( 8192 );
2662             rtl_TextEncoding eEncoding = gsl_getSystemTextEncoding();
2663 
2664             String aDummy;              // Erkennungszeichen fuer neue Streams
2665             refList->WriteByteString( aDummy, RTL_TEXTENCODING_MS_1252 )
2666                      << (sal_uInt8) 4       // Laenge des Headers (ohne den Leerstring)
2667                      << (sal_uInt16)WORDLIST_VERSION_358    // Version des Streams
2668                      << (sal_uInt8)eEncoding;               // der Zeichensatz
2669 
2670             for( sal_uInt16 i = 0; i < pAutocorr_List->Count() &&
2671                                 SVSTREAM_OK == refList->GetError(); ++i )
2672             {
2673                 SvxAutocorrWord* p = pAutocorr_List->GetObject( i );
2674                 refList->WriteByteString( p->GetShort(), eEncoding ).
2675                         WriteByteString(  p->IsTextOnly()
2676                                             ? p->GetLong()
2677                                             : p->GetShort(), eEncoding );
2678             }
2679             refList->Commit();
2680             bRet = SVSTREAM_OK == refList->GetError();
2681             if( bRet )
2682             {
2683                 refList.Clear();
2684                 rStg.Commit();
2685                 if( SVSTREAM_OK != rStg.GetError() )
2686                 {
2687                     bRemove = sal_True;
2688                     bRet = sal_False;
2689                 }
2690             }
2691             */
2692         }
2693         else
2694             bRet = sal_False;
2695     }
2696 
2697     if( bRemove )
2698     {
2699         rStg.Remove( sStrmName );
2700         rStg.Commit();
2701     }
2702 
2703     return bRet;
2704 }
2705 
2706 /* -----------------18.11.98 11:26-------------------
2707  *
2708  * --------------------------------------------------*/
PutText(const String & rShort,const String & rLong)2709 sal_Bool SvxAutoCorrectLanguageLists::PutText( const String& rShort,
2710                                            const String& rLong )
2711 {
2712     // erstmal akt. Liste besorgen!
2713     GetAutocorrWordList();
2714 
2715     MakeUserStorage_Impl();
2716     SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2717 
2718     sal_Bool bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError();
2719 
2720 /*  if( bRet )
2721     {
2722         // PutText( *xStg, rShort );
2723     }
2724 */
2725     // die Wortliste aktualisieren
2726     if( bRet )
2727     {
2728         sal_uInt16 nPos;
2729         SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, rLong, sal_True );
2730         if( pAutocorr_List->Seek_Entry( pNew, &nPos ) )
2731         {
2732             if( !(*pAutocorr_List)[ nPos ]->IsTextOnly() )
2733             {
2734                 // dann ist der Storage noch zu entfernen
2735                 String sStgNm( rShort );
2736                 if (xStg->IsOLEStorage())
2737                     EncryptBlockName_Imp( sStgNm );
2738                 else
2739                     GeneratePackageName ( rShort, sStgNm);
2740 
2741                 if( xStg->IsContained( sStgNm ) )
2742                     xStg->Remove( sStgNm );
2743             }
2744             pAutocorr_List->DeleteAndDestroy( nPos );
2745         }
2746 
2747         if( pAutocorr_List->Insert( pNew ) )
2748         {
2749             bRet = MakeBlocklist_Imp( *xStg );
2750             xStg = 0;
2751         }
2752         else
2753         {
2754             delete pNew;
2755             bRet = sal_False;
2756         }
2757     }
2758     return bRet;
2759 }
2760 /* -----------------18.11.98 11:26-------------------
2761  *
2762  * --------------------------------------------------*/
2763     //  - Text mit Attributierung (kann nur der SWG - SWG-Format!)
PutText(const String & rShort,SfxObjectShell & rShell)2764 sal_Bool SvxAutoCorrectLanguageLists::PutText( const String& rShort,
2765                                         SfxObjectShell& rShell )
2766 {
2767     // erstmal akt. Liste besorgen!
2768     GetAutocorrWordList();
2769 
2770     MakeUserStorage_Impl();
2771 
2772     sal_Bool bRet = sal_False;
2773     String sLong;
2774     try
2775     {
2776         uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sUserAutoCorrFile, embed::ElementModes::READWRITE );
2777 //      String aName( rShort );
2778 //      EncryptBlockName_Imp( aName );
2779 //      bRet = PutText( *xStg, aName, rShell, sLong );
2780         bRet = rAutoCorrect.PutText( xStg, sUserAutoCorrFile, rShort, rShell, sLong );
2781         xStg = 0;
2782 
2783         // die Wortliste aktualisieren
2784         if( bRet )
2785         {
2786             SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, sLong, sal_False );
2787             if( pAutocorr_List->Insert( pNew ) )
2788             {
2789                 SotStorageRef xStor = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2790                 MakeBlocklist_Imp( *xStor );
2791             }
2792             else
2793                 delete pNew;
2794         }
2795     }
2796     catch ( uno::Exception& )
2797     {
2798     }
2799 
2800     return bRet;
2801 }
2802 
2803 /* -----------------18.11.98 11:26-------------------
2804  *
2805  * --------------------------------------------------*/
2806     //  - loesche einen Eintrag
DeleteText(const String & rShort)2807 sal_Bool SvxAutoCorrectLanguageLists::DeleteText( const String& rShort )
2808 {
2809     // erstmal akt. Liste besorgen!
2810     GetAutocorrWordList();
2811 
2812     MakeUserStorage_Impl();
2813 
2814     SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2815     sal_Bool bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError();
2816     if( bRet )
2817     {
2818         sal_uInt16 nPos;
2819         SvxAutocorrWord aTmp( rShort, rShort );
2820         if( pAutocorr_List->Seek_Entry( &aTmp, &nPos ) )
2821         {
2822             SvxAutocorrWord* pFnd = (*pAutocorr_List)[ nPos ];
2823             if( !pFnd->IsTextOnly() )
2824             {
2825                 String aName( rShort );
2826                 if (xStg->IsOLEStorage())
2827                     EncryptBlockName_Imp( aName );
2828                 else
2829                     GeneratePackageName ( rShort, aName );
2830                 if( xStg->IsContained( aName ) )
2831                 {
2832                     xStg->Remove( aName );
2833                     bRet = xStg->Commit();
2834                 }
2835 
2836             }
2837             // die Wortliste aktualisieren
2838             pAutocorr_List->DeleteAndDestroy( nPos );
2839             MakeBlocklist_Imp( *xStg );
2840             xStg = 0;
2841         }
2842         else
2843             bRet = sal_False;
2844     }
2845     return bRet;
2846 }
2847