1*3b8558fdSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*3b8558fdSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*3b8558fdSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*3b8558fdSAndrew Rist * distributed with this work for additional information 6*3b8558fdSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*3b8558fdSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*3b8558fdSAndrew Rist * "License"); you may not use this file except in compliance 9*3b8558fdSAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*3b8558fdSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*3b8558fdSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*3b8558fdSAndrew Rist * software distributed under the License is distributed on an 15*3b8558fdSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*3b8558fdSAndrew Rist * KIND, either express or implied. See the License for the 17*3b8558fdSAndrew Rist * specific language governing permissions and limitations 18*3b8558fdSAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*3b8558fdSAndrew Rist *************************************************************/ 21*3b8558fdSAndrew Rist 22*3b8558fdSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_linguistic.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include <cppuhelper/factory.hxx> 28cdf0e10cSrcweir #include <dicimp.hxx> 29cdf0e10cSrcweir #include <hyphdsp.hxx> 30cdf0e10cSrcweir #include <i18npool/lang.h> 31cdf0e10cSrcweir #include <i18npool/mslangid.hxx> 32cdf0e10cSrcweir #include <osl/mutex.hxx> 33cdf0e10cSrcweir #include <tools/debug.hxx> 34cdf0e10cSrcweir #include <tools/fsys.hxx> 35cdf0e10cSrcweir #include <tools/stream.hxx> 36cdf0e10cSrcweir #include <tools/string.hxx> 37cdf0e10cSrcweir #include <tools/urlobj.hxx> 38cdf0e10cSrcweir #include <unotools/processfactory.hxx> 39cdf0e10cSrcweir #include <unotools/ucbstreamhelper.hxx> 40cdf0e10cSrcweir 41cdf0e10cSrcweir #include <com/sun/star/ucb/XSimpleFileAccess.hpp> 42cdf0e10cSrcweir #include <com/sun/star/linguistic2/DictionaryType.hpp> 43cdf0e10cSrcweir #include <com/sun/star/linguistic2/DictionaryEventFlags.hpp> 44cdf0e10cSrcweir #include <com/sun/star/registry/XRegistryKey.hpp> 45cdf0e10cSrcweir #include <com/sun/star/io/XInputStream.hpp> 46cdf0e10cSrcweir #include <com/sun/star/io/XOutputStream.hpp> 47cdf0e10cSrcweir 48cdf0e10cSrcweir #include "defs.hxx" 49cdf0e10cSrcweir 50cdf0e10cSrcweir 51cdf0e10cSrcweir using namespace utl; 52cdf0e10cSrcweir using namespace osl; 53cdf0e10cSrcweir using namespace rtl; 54cdf0e10cSrcweir using namespace com::sun::star; 55cdf0e10cSrcweir using namespace com::sun::star::lang; 56cdf0e10cSrcweir using namespace com::sun::star::uno; 57cdf0e10cSrcweir using namespace com::sun::star::linguistic2; 58cdf0e10cSrcweir using namespace linguistic; 59cdf0e10cSrcweir 60cdf0e10cSrcweir /////////////////////////////////////////////////////////////////////////// 61cdf0e10cSrcweir 62cdf0e10cSrcweir #define BUFSIZE 4096 63cdf0e10cSrcweir #define VERS2_NOLANGUAGE 1024 64cdf0e10cSrcweir 65cdf0e10cSrcweir #define MAX_HEADER_LENGTH 16 66cdf0e10cSrcweir 67cdf0e10cSrcweir static const sal_Char* pDicExt = "dic"; 68cdf0e10cSrcweir static const sal_Char* pVerStr2 = "WBSWG2"; 69cdf0e10cSrcweir static const sal_Char* pVerStr5 = "WBSWG5"; 70cdf0e10cSrcweir static const sal_Char* pVerStr6 = "WBSWG6"; 71cdf0e10cSrcweir static const sal_Char* pVerOOo7 = "OOoUserDict1"; 72cdf0e10cSrcweir 73cdf0e10cSrcweir static const sal_Int16 DIC_VERSION_DONTKNOW = -1; 74cdf0e10cSrcweir static const sal_Int16 DIC_VERSION_2 = 2; 75cdf0e10cSrcweir static const sal_Int16 DIC_VERSION_5 = 5; 76cdf0e10cSrcweir static const sal_Int16 DIC_VERSION_6 = 6; 77cdf0e10cSrcweir static const sal_Int16 DIC_VERSION_7 = 7; 78cdf0e10cSrcweir 79cdf0e10cSrcweir static sal_Bool getTag(const ByteString &rLine, 80cdf0e10cSrcweir const sal_Char *pTagName, ByteString &rTagValue) 81cdf0e10cSrcweir { 82cdf0e10cSrcweir xub_StrLen nPos = rLine.Search( pTagName ); 83cdf0e10cSrcweir if (nPos == STRING_NOTFOUND) 84cdf0e10cSrcweir return sal_False; 85cdf0e10cSrcweir 86cdf0e10cSrcweir rTagValue = rLine.Copy( nPos + sal::static_int_cast< xub_StrLen >(strlen( pTagName )) ).EraseLeadingAndTrailingChars(); 87cdf0e10cSrcweir return sal_True; 88cdf0e10cSrcweir } 89cdf0e10cSrcweir 90cdf0e10cSrcweir 91cdf0e10cSrcweir sal_Int16 ReadDicVersion( SvStreamPtr &rpStream, sal_uInt16 &nLng, sal_Bool &bNeg ) 92cdf0e10cSrcweir { 93cdf0e10cSrcweir // Sniff the header 94cdf0e10cSrcweir sal_Int16 nDicVersion = DIC_VERSION_DONTKNOW; 95cdf0e10cSrcweir sal_Char pMagicHeader[MAX_HEADER_LENGTH]; 96cdf0e10cSrcweir 97cdf0e10cSrcweir nLng = LANGUAGE_NONE; 98cdf0e10cSrcweir bNeg = sal_False; 99cdf0e10cSrcweir 100cdf0e10cSrcweir if (!rpStream.get() || rpStream->GetError()) 101cdf0e10cSrcweir return -1; 102cdf0e10cSrcweir 103cdf0e10cSrcweir sal_Size nSniffPos = rpStream->Tell(); 104cdf0e10cSrcweir static sal_Size nVerOOo7Len = sal::static_int_cast< sal_Size >(strlen( pVerOOo7 )); 105cdf0e10cSrcweir pMagicHeader[ nVerOOo7Len ] = '\0'; 106cdf0e10cSrcweir if ((rpStream->Read((void *) pMagicHeader, nVerOOo7Len) == nVerOOo7Len) && 107cdf0e10cSrcweir !strcmp(pMagicHeader, pVerOOo7)) 108cdf0e10cSrcweir { 109cdf0e10cSrcweir sal_Bool bSuccess; 110cdf0e10cSrcweir ByteString aLine; 111cdf0e10cSrcweir 112cdf0e10cSrcweir nDicVersion = DIC_VERSION_7; 113cdf0e10cSrcweir 114cdf0e10cSrcweir // 1st skip magic / header line 115cdf0e10cSrcweir rpStream->ReadLine(aLine); 116cdf0e10cSrcweir 117cdf0e10cSrcweir // 2nd line: language all | en-US | pt-BR ... 118cdf0e10cSrcweir while (sal_True == (bSuccess = rpStream->ReadLine(aLine))) 119cdf0e10cSrcweir { 120cdf0e10cSrcweir ByteString aTagValue; 121cdf0e10cSrcweir 122cdf0e10cSrcweir if (aLine.GetChar(0) == '#') // skip comments 123cdf0e10cSrcweir continue; 124cdf0e10cSrcweir 125cdf0e10cSrcweir // lang: field 126cdf0e10cSrcweir if (getTag(aLine, "lang: ", aTagValue)) 127cdf0e10cSrcweir { 128cdf0e10cSrcweir if (aTagValue == "<none>") 129cdf0e10cSrcweir nLng = LANGUAGE_NONE; 130cdf0e10cSrcweir else 131cdf0e10cSrcweir nLng = MsLangId::convertIsoStringToLanguage(OUString(aTagValue.GetBuffer(), 132cdf0e10cSrcweir aTagValue.Len(), RTL_TEXTENCODING_ASCII_US)); 133cdf0e10cSrcweir } 134cdf0e10cSrcweir 135cdf0e10cSrcweir // type: negative / positive 136cdf0e10cSrcweir if (getTag(aLine, "type: ", aTagValue)) 137cdf0e10cSrcweir { 138cdf0e10cSrcweir if (aTagValue == "negative") 139cdf0e10cSrcweir bNeg = sal_True; 140cdf0e10cSrcweir else 141cdf0e10cSrcweir bNeg = sal_False; 142cdf0e10cSrcweir } 143cdf0e10cSrcweir 144cdf0e10cSrcweir if (aLine.Search ("---") != STRING_NOTFOUND) // end of header 145cdf0e10cSrcweir break; 146cdf0e10cSrcweir } 147cdf0e10cSrcweir if (!bSuccess) 148cdf0e10cSrcweir return -2; 149cdf0e10cSrcweir } 150cdf0e10cSrcweir else 151cdf0e10cSrcweir { 152cdf0e10cSrcweir sal_uInt16 nLen; 153cdf0e10cSrcweir 154cdf0e10cSrcweir rpStream->Seek (nSniffPos ); 155cdf0e10cSrcweir 156cdf0e10cSrcweir *rpStream >> nLen; 157cdf0e10cSrcweir if (nLen >= MAX_HEADER_LENGTH) 158cdf0e10cSrcweir return -1; 159cdf0e10cSrcweir 160cdf0e10cSrcweir rpStream->Read(pMagicHeader, nLen); 161cdf0e10cSrcweir pMagicHeader[nLen] = '\0'; 162cdf0e10cSrcweir 163cdf0e10cSrcweir // Check version magic 164cdf0e10cSrcweir if (0 == strcmp( pMagicHeader, pVerStr6 )) 165cdf0e10cSrcweir nDicVersion = DIC_VERSION_6; 166cdf0e10cSrcweir else if (0 == strcmp( pMagicHeader, pVerStr5 )) 167cdf0e10cSrcweir nDicVersion = DIC_VERSION_5; 168cdf0e10cSrcweir else if (0 == strcmp( pMagicHeader, pVerStr2 )) 169cdf0e10cSrcweir nDicVersion = DIC_VERSION_2; 170cdf0e10cSrcweir else 171cdf0e10cSrcweir nDicVersion = DIC_VERSION_DONTKNOW; 172cdf0e10cSrcweir 173cdf0e10cSrcweir if (DIC_VERSION_2 == nDicVersion || 174cdf0e10cSrcweir DIC_VERSION_5 == nDicVersion || 175cdf0e10cSrcweir DIC_VERSION_6 == nDicVersion) 176cdf0e10cSrcweir { 177cdf0e10cSrcweir // The language of the dictionary 178cdf0e10cSrcweir *rpStream >> nLng; 179cdf0e10cSrcweir 180cdf0e10cSrcweir if (VERS2_NOLANGUAGE == nLng) 181cdf0e10cSrcweir nLng = LANGUAGE_NONE; 182cdf0e10cSrcweir 183cdf0e10cSrcweir // Negative Flag 184cdf0e10cSrcweir sal_Char nTmp; 185cdf0e10cSrcweir *rpStream >> nTmp; 186cdf0e10cSrcweir bNeg = (sal_Bool)nTmp; 187cdf0e10cSrcweir } 188cdf0e10cSrcweir } 189cdf0e10cSrcweir 190cdf0e10cSrcweir return nDicVersion; 191cdf0e10cSrcweir } 192cdf0e10cSrcweir 193cdf0e10cSrcweir 194cdf0e10cSrcweir 195cdf0e10cSrcweir const String GetDicExtension() 196cdf0e10cSrcweir { 197cdf0e10cSrcweir return String::CreateFromAscii( pDicExt ); 198cdf0e10cSrcweir } 199cdf0e10cSrcweir 200cdf0e10cSrcweir /////////////////////////////////////////////////////////////////////////// 201cdf0e10cSrcweir 202cdf0e10cSrcweir DictionaryNeo::DictionaryNeo() : 203cdf0e10cSrcweir aDicEvtListeners( GetLinguMutex() ), 204cdf0e10cSrcweir eDicType (DictionaryType_POSITIVE), 205cdf0e10cSrcweir nLanguage (LANGUAGE_NONE) 206cdf0e10cSrcweir { 207cdf0e10cSrcweir nCount = 0; 208cdf0e10cSrcweir nDicVersion = DIC_VERSION_DONTKNOW; 209cdf0e10cSrcweir bNeedEntries = sal_False; 210cdf0e10cSrcweir bIsModified = bIsActive = sal_False; 211cdf0e10cSrcweir bIsReadonly = sal_False; 212cdf0e10cSrcweir } 213cdf0e10cSrcweir 214cdf0e10cSrcweir DictionaryNeo::DictionaryNeo(const OUString &rName, 215cdf0e10cSrcweir sal_Int16 nLang, DictionaryType eType, 216cdf0e10cSrcweir const OUString &rMainURL, 217cdf0e10cSrcweir sal_Bool bWriteable) : 218cdf0e10cSrcweir aDicEvtListeners( GetLinguMutex() ), 219cdf0e10cSrcweir aDicName (rName), 220cdf0e10cSrcweir aMainURL (rMainURL), 221cdf0e10cSrcweir eDicType (eType), 222cdf0e10cSrcweir nLanguage (nLang) 223cdf0e10cSrcweir { 224cdf0e10cSrcweir nCount = 0; 225cdf0e10cSrcweir nDicVersion = DIC_VERSION_DONTKNOW; 226cdf0e10cSrcweir bNeedEntries = sal_True; 227cdf0e10cSrcweir bIsModified = bIsActive = sal_False; 228cdf0e10cSrcweir bIsReadonly = !bWriteable; 229cdf0e10cSrcweir 230cdf0e10cSrcweir if( rMainURL.getLength() > 0 ) 231cdf0e10cSrcweir { 232cdf0e10cSrcweir sal_Bool bExists = FileExists( rMainURL ); 233cdf0e10cSrcweir if( !bExists ) 234cdf0e10cSrcweir { 235cdf0e10cSrcweir // save new dictionaries with in Format 7 (UTF8 plain text) 236cdf0e10cSrcweir nDicVersion = DIC_VERSION_7; 237cdf0e10cSrcweir 238cdf0e10cSrcweir //! create physical representation of an **empty** dictionary 239cdf0e10cSrcweir //! that could be found by the dictionary-list implementation 240cdf0e10cSrcweir // (Note: empty dictionaries are not just empty files!) 241cdf0e10cSrcweir DBG_ASSERT( !bIsReadonly, 242cdf0e10cSrcweir "DictionaryNeo: dictionaries should be writeable if they are to be saved" ); 243cdf0e10cSrcweir if (!bIsReadonly) 244cdf0e10cSrcweir saveEntries( rMainURL ); 245cdf0e10cSrcweir bNeedEntries = sal_False; 246cdf0e10cSrcweir } 247cdf0e10cSrcweir } 248cdf0e10cSrcweir else 249cdf0e10cSrcweir { 250cdf0e10cSrcweir // non persistent dictionaries (like IgnoreAllList) should always be writable 251cdf0e10cSrcweir bIsReadonly = sal_False; 252cdf0e10cSrcweir bNeedEntries = sal_False; 253cdf0e10cSrcweir } 254cdf0e10cSrcweir } 255cdf0e10cSrcweir 256cdf0e10cSrcweir DictionaryNeo::~DictionaryNeo() 257cdf0e10cSrcweir { 258cdf0e10cSrcweir } 259cdf0e10cSrcweir 260cdf0e10cSrcweir sal_uLong DictionaryNeo::loadEntries(const OUString &rMainURL) 261cdf0e10cSrcweir { 262cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 263cdf0e10cSrcweir 264cdf0e10cSrcweir // counter check that it is safe to set bIsModified to sal_False at 265cdf0e10cSrcweir // the end of the function 266cdf0e10cSrcweir DBG_ASSERT(!bIsModified, "lng : dictionary already modified!"); 267cdf0e10cSrcweir 268cdf0e10cSrcweir // function should only be called once in order to load entries from file 269cdf0e10cSrcweir bNeedEntries = sal_False; 270cdf0e10cSrcweir 271cdf0e10cSrcweir if (rMainURL.getLength() == 0) 272cdf0e10cSrcweir return 0; 273cdf0e10cSrcweir 274cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() ); 275cdf0e10cSrcweir 276cdf0e10cSrcweir // get XInputStream stream 277cdf0e10cSrcweir uno::Reference< io::XInputStream > xStream; 278cdf0e10cSrcweir try 279cdf0e10cSrcweir { 280cdf0e10cSrcweir uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance( 281cdf0e10cSrcweir A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW ); 282cdf0e10cSrcweir xStream = xAccess->openFileRead( rMainURL ); 283cdf0e10cSrcweir } 284cdf0e10cSrcweir catch (uno::Exception & e) 285cdf0e10cSrcweir { 286cdf0e10cSrcweir DBG_ASSERT( 0, "failed to get input stream" ); 287cdf0e10cSrcweir (void) e; 288cdf0e10cSrcweir } 289cdf0e10cSrcweir if (!xStream.is()) 290cdf0e10cSrcweir return static_cast< sal_uLong >(-1); 291cdf0e10cSrcweir 292cdf0e10cSrcweir SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) ); 293cdf0e10cSrcweir 294cdf0e10cSrcweir sal_uLong nErr = sal::static_int_cast< sal_uLong >(-1); 295cdf0e10cSrcweir 296cdf0e10cSrcweir // Header einlesen 297cdf0e10cSrcweir sal_Bool bNegativ; 298cdf0e10cSrcweir sal_uInt16 nLang; 299cdf0e10cSrcweir nDicVersion = ReadDicVersion(pStream, nLang, bNegativ); 300cdf0e10cSrcweir if (0 != (nErr = pStream->GetError())) 301cdf0e10cSrcweir return nErr; 302cdf0e10cSrcweir 303cdf0e10cSrcweir nLanguage = nLang; 304cdf0e10cSrcweir 305cdf0e10cSrcweir eDicType = bNegativ ? DictionaryType_NEGATIVE : DictionaryType_POSITIVE; 306cdf0e10cSrcweir 307cdf0e10cSrcweir rtl_TextEncoding eEnc = osl_getThreadTextEncoding(); 308cdf0e10cSrcweir if (nDicVersion >= DIC_VERSION_6) 309cdf0e10cSrcweir eEnc = RTL_TEXTENCODING_UTF8; 310cdf0e10cSrcweir nCount = 0; 311cdf0e10cSrcweir 312cdf0e10cSrcweir if (DIC_VERSION_6 == nDicVersion || 313cdf0e10cSrcweir DIC_VERSION_5 == nDicVersion || 314cdf0e10cSrcweir DIC_VERSION_2 == nDicVersion) 315cdf0e10cSrcweir { 316cdf0e10cSrcweir sal_uInt16 nLen = 0; 317cdf0e10cSrcweir sal_Char aWordBuf[ BUFSIZE ]; 318cdf0e10cSrcweir 319cdf0e10cSrcweir // Das erste Wort einlesen 320cdf0e10cSrcweir if (!pStream->IsEof()) 321cdf0e10cSrcweir { 322cdf0e10cSrcweir *pStream >> nLen; 323cdf0e10cSrcweir if (0 != (nErr = pStream->GetError())) 324cdf0e10cSrcweir return nErr; 325cdf0e10cSrcweir if ( nLen < BUFSIZE ) 326cdf0e10cSrcweir { 327cdf0e10cSrcweir pStream->Read(aWordBuf, nLen); 328cdf0e10cSrcweir if (0 != (nErr = pStream->GetError())) 329cdf0e10cSrcweir return nErr; 330cdf0e10cSrcweir *(aWordBuf + nLen) = 0; 331cdf0e10cSrcweir } 332cdf0e10cSrcweir } 333cdf0e10cSrcweir 334cdf0e10cSrcweir while(!pStream->IsEof()) 335cdf0e10cSrcweir { 336cdf0e10cSrcweir // Aus dem File einlesen 337cdf0e10cSrcweir // Einfuegen ins Woerterbuch ohne Konvertierung 338cdf0e10cSrcweir if(*aWordBuf) 339cdf0e10cSrcweir { 340cdf0e10cSrcweir ByteString aDummy( aWordBuf ); 341cdf0e10cSrcweir String aText( aDummy, eEnc ); 342cdf0e10cSrcweir uno::Reference< XDictionaryEntry > xEntry = 343cdf0e10cSrcweir new DicEntry( aText, bNegativ ); 344cdf0e10cSrcweir addEntry_Impl( xEntry , sal_True ); //! don't launch events here 345cdf0e10cSrcweir } 346cdf0e10cSrcweir 347cdf0e10cSrcweir *pStream >> nLen; 348cdf0e10cSrcweir if (pStream->IsEof()) // #75082# GPF in online-spelling 349cdf0e10cSrcweir break; 350cdf0e10cSrcweir if (0 != (nErr = pStream->GetError())) 351cdf0e10cSrcweir return nErr; 352cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS 353cdf0e10cSrcweir if (nLen >= BUFSIZE) 354cdf0e10cSrcweir throw io::IOException() ; 355cdf0e10cSrcweir #endif 356cdf0e10cSrcweir 357cdf0e10cSrcweir if (nLen < BUFSIZE) 358cdf0e10cSrcweir { 359cdf0e10cSrcweir pStream->Read(aWordBuf, nLen); 360cdf0e10cSrcweir if (0 != (nErr = pStream->GetError())) 361cdf0e10cSrcweir return nErr; 362cdf0e10cSrcweir } 363cdf0e10cSrcweir else 364cdf0e10cSrcweir return SVSTREAM_READ_ERROR; 365cdf0e10cSrcweir *(aWordBuf + nLen) = 0; 366cdf0e10cSrcweir } 367cdf0e10cSrcweir } 368cdf0e10cSrcweir else if (DIC_VERSION_7 == nDicVersion) 369cdf0e10cSrcweir { 370cdf0e10cSrcweir sal_Bool bSuccess; 371cdf0e10cSrcweir ByteString aLine; 372cdf0e10cSrcweir 373cdf0e10cSrcweir // remaining lines - stock strings (a [==] b) 374cdf0e10cSrcweir while (sal_True == (bSuccess = pStream->ReadLine(aLine))) 375cdf0e10cSrcweir { 376cdf0e10cSrcweir if (aLine.GetChar(0) == '#') // skip comments 377cdf0e10cSrcweir continue; 378cdf0e10cSrcweir rtl::OUString aText = rtl::OStringToOUString (aLine, RTL_TEXTENCODING_UTF8); 379cdf0e10cSrcweir uno::Reference< XDictionaryEntry > xEntry = 380cdf0e10cSrcweir new DicEntry( aText, eDicType == DictionaryType_NEGATIVE ); 381cdf0e10cSrcweir addEntry_Impl( xEntry , sal_True ); //! don't launch events here 382cdf0e10cSrcweir } 383cdf0e10cSrcweir } 384cdf0e10cSrcweir 385cdf0e10cSrcweir DBG_ASSERT(isSorted(), "lng : dictionary is not sorted"); 386cdf0e10cSrcweir 387cdf0e10cSrcweir // since this routine should be called only initialy (prior to any 388cdf0e10cSrcweir // modification to be saved) we reset the bIsModified flag here that 389cdf0e10cSrcweir // was implicitly set by addEntry_Impl 390cdf0e10cSrcweir bIsModified = sal_False; 391cdf0e10cSrcweir 392cdf0e10cSrcweir return pStream->GetError(); 393cdf0e10cSrcweir } 394cdf0e10cSrcweir 395cdf0e10cSrcweir 396cdf0e10cSrcweir static ByteString formatForSave( 397cdf0e10cSrcweir const uno::Reference< XDictionaryEntry > &xEntry, rtl_TextEncoding eEnc ) 398cdf0e10cSrcweir { 399cdf0e10cSrcweir ByteString aStr(xEntry->getDictionaryWord().getStr(), eEnc); 400cdf0e10cSrcweir 401cdf0e10cSrcweir if (xEntry->isNegative()) 402cdf0e10cSrcweir { 403cdf0e10cSrcweir aStr += "=="; 404cdf0e10cSrcweir aStr += ByteString(xEntry->getReplacementText().getStr(), eEnc); 405cdf0e10cSrcweir } 406cdf0e10cSrcweir return aStr; 407cdf0e10cSrcweir } 408cdf0e10cSrcweir 409cdf0e10cSrcweir 410cdf0e10cSrcweir sal_uLong DictionaryNeo::saveEntries(const OUString &rURL) 411cdf0e10cSrcweir { 412cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 413cdf0e10cSrcweir 414cdf0e10cSrcweir if (rURL.getLength() == 0) 415cdf0e10cSrcweir return 0; 416cdf0e10cSrcweir DBG_ASSERT(!INetURLObject( rURL ).HasError(), "lng : invalid URL"); 417cdf0e10cSrcweir 418cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() ); 419cdf0e10cSrcweir 420cdf0e10cSrcweir // get XOutputStream stream 421cdf0e10cSrcweir uno::Reference< io::XStream > xStream; 422cdf0e10cSrcweir try 423cdf0e10cSrcweir { 424cdf0e10cSrcweir uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance( 425cdf0e10cSrcweir A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW ); 426cdf0e10cSrcweir xStream = xAccess->openFileReadWrite( rURL ); 427cdf0e10cSrcweir } 428cdf0e10cSrcweir catch (uno::Exception & e) 429cdf0e10cSrcweir { 430cdf0e10cSrcweir DBG_ASSERT( 0, "failed to get input stream" ); 431cdf0e10cSrcweir (void) e; 432cdf0e10cSrcweir } 433cdf0e10cSrcweir if (!xStream.is()) 434cdf0e10cSrcweir return static_cast< sal_uLong >(-1); 435cdf0e10cSrcweir 436cdf0e10cSrcweir SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) ); 437cdf0e10cSrcweir sal_uLong nErr = sal::static_int_cast< sal_uLong >(-1); 438cdf0e10cSrcweir 439cdf0e10cSrcweir // 440cdf0e10cSrcweir // Always write as the latest version, i.e. DIC_VERSION_7 441cdf0e10cSrcweir // 442cdf0e10cSrcweir rtl_TextEncoding eEnc = RTL_TEXTENCODING_UTF8; 443cdf0e10cSrcweir pStream->WriteLine(ByteString (pVerOOo7)); 444cdf0e10cSrcweir if (0 != (nErr = pStream->GetError())) 445cdf0e10cSrcweir return nErr; 446cdf0e10cSrcweir if (nLanguage == LANGUAGE_NONE) 447cdf0e10cSrcweir pStream->WriteLine(ByteString("lang: <none>")); 448cdf0e10cSrcweir else 449cdf0e10cSrcweir { 450cdf0e10cSrcweir ByteString aLine("lang: "); 451cdf0e10cSrcweir aLine += ByteString( String( MsLangId::convertLanguageToIsoString( nLanguage ) ), eEnc); 452cdf0e10cSrcweir pStream->WriteLine( aLine ); 453cdf0e10cSrcweir } 454cdf0e10cSrcweir if (0 != (nErr = pStream->GetError())) 455cdf0e10cSrcweir return nErr; 456cdf0e10cSrcweir if (eDicType == DictionaryType_POSITIVE) 457cdf0e10cSrcweir pStream->WriteLine(ByteString("type: positive")); 458cdf0e10cSrcweir else 459cdf0e10cSrcweir pStream->WriteLine(ByteString("type: negative")); 460cdf0e10cSrcweir if (0 != (nErr = pStream->GetError())) 461cdf0e10cSrcweir return nErr; 462cdf0e10cSrcweir pStream->WriteLine(ByteString("---")); 463cdf0e10cSrcweir if (0 != (nErr = pStream->GetError())) 464cdf0e10cSrcweir return nErr; 465cdf0e10cSrcweir const uno::Reference< XDictionaryEntry > *pEntry = aEntries.getConstArray(); 466cdf0e10cSrcweir for (sal_Int32 i = 0; i < nCount; i++) 467cdf0e10cSrcweir { 468cdf0e10cSrcweir ByteString aOutStr = formatForSave(pEntry[i], eEnc); 469cdf0e10cSrcweir pStream->WriteLine (aOutStr); 470cdf0e10cSrcweir if (0 != (nErr = pStream->GetError())) 471cdf0e10cSrcweir return nErr; 472cdf0e10cSrcweir } 473cdf0e10cSrcweir 474cdf0e10cSrcweir //If we are migrating from an older version, then on first successful 475cdf0e10cSrcweir //write, we're now converted to the latest version, i.e. DIC_VERSION_7 476cdf0e10cSrcweir nDicVersion = DIC_VERSION_7; 477cdf0e10cSrcweir 478cdf0e10cSrcweir return nErr; 479cdf0e10cSrcweir } 480cdf0e10cSrcweir 481cdf0e10cSrcweir void DictionaryNeo::launchEvent(sal_Int16 nEvent, 482cdf0e10cSrcweir uno::Reference< XDictionaryEntry > xEntry) 483cdf0e10cSrcweir { 484cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 485cdf0e10cSrcweir 486cdf0e10cSrcweir DictionaryEvent aEvt; 487cdf0e10cSrcweir aEvt.Source = uno::Reference< XDictionary >( this ); 488cdf0e10cSrcweir aEvt.nEvent = nEvent; 489cdf0e10cSrcweir aEvt.xDictionaryEntry = xEntry; 490cdf0e10cSrcweir 491cdf0e10cSrcweir cppu::OInterfaceIteratorHelper aIt( aDicEvtListeners ); 492cdf0e10cSrcweir while (aIt.hasMoreElements()) 493cdf0e10cSrcweir { 494cdf0e10cSrcweir uno::Reference< XDictionaryEventListener > xRef( aIt.next(), UNO_QUERY ); 495cdf0e10cSrcweir if (xRef.is()) 496cdf0e10cSrcweir xRef->processDictionaryEvent( aEvt ); 497cdf0e10cSrcweir } 498cdf0e10cSrcweir } 499cdf0e10cSrcweir 500cdf0e10cSrcweir int DictionaryNeo::cmpDicEntry(const OUString& rWord1, 501cdf0e10cSrcweir const OUString &rWord2, 502cdf0e10cSrcweir sal_Bool bSimilarOnly) 503cdf0e10cSrcweir { 504cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 505cdf0e10cSrcweir 506cdf0e10cSrcweir // returns 0 if rWord1 is equal to rWord2 507cdf0e10cSrcweir // " a value < 0 if rWord1 is less than rWord2 508cdf0e10cSrcweir // " a value > 0 if rWord1 is greater than rWord2 509cdf0e10cSrcweir 510cdf0e10cSrcweir int nRes = 0; 511cdf0e10cSrcweir 512cdf0e10cSrcweir OUString aWord1( rWord1 ), 513cdf0e10cSrcweir aWord2( rWord2 ); 514cdf0e10cSrcweir sal_Int32 nLen1 = aWord1.getLength(), 515cdf0e10cSrcweir nLen2 = aWord2.getLength(); 516cdf0e10cSrcweir if (bSimilarOnly) 517cdf0e10cSrcweir { 518cdf0e10cSrcweir const sal_Unicode cChar = '.'; 519cdf0e10cSrcweir if (nLen1 && cChar == aWord1[ nLen1 - 1 ]) 520cdf0e10cSrcweir nLen1--; 521cdf0e10cSrcweir if (nLen2 && cChar == aWord2[ nLen2 - 1 ]) 522cdf0e10cSrcweir nLen2--; 523cdf0e10cSrcweir } 524cdf0e10cSrcweir 525cdf0e10cSrcweir const sal_Unicode cIgnChar = '='; 526cdf0e10cSrcweir sal_Int32 nIdx1 = 0, 527cdf0e10cSrcweir nIdx2 = 0, 528cdf0e10cSrcweir nNumIgnChar1 = 0, 529cdf0e10cSrcweir nNumIgnChar2 = 0; 530cdf0e10cSrcweir 531cdf0e10cSrcweir sal_Int32 nDiff = 0; 532cdf0e10cSrcweir sal_Unicode cChar1 = '\0'; 533cdf0e10cSrcweir sal_Unicode cChar2 = '\0'; 534cdf0e10cSrcweir do 535cdf0e10cSrcweir { 536cdf0e10cSrcweir // skip chars to be ignored 537cdf0e10cSrcweir while (nIdx1 < nLen1 && (cChar1 = aWord1[ nIdx1 ]) == cIgnChar) 538cdf0e10cSrcweir { 539cdf0e10cSrcweir nIdx1++; 540cdf0e10cSrcweir nNumIgnChar1++; 541cdf0e10cSrcweir } 542cdf0e10cSrcweir while (nIdx2 < nLen2 && (cChar2 = aWord2[ nIdx2 ]) == cIgnChar) 543cdf0e10cSrcweir { 544cdf0e10cSrcweir nIdx2++; 545cdf0e10cSrcweir nNumIgnChar2++; 546cdf0e10cSrcweir } 547cdf0e10cSrcweir 548cdf0e10cSrcweir if (nIdx1 < nLen1 && nIdx2 < nLen2) 549cdf0e10cSrcweir { 550cdf0e10cSrcweir nDiff = cChar1 - cChar2; 551cdf0e10cSrcweir if (nDiff) 552cdf0e10cSrcweir break; 553cdf0e10cSrcweir nIdx1++; 554cdf0e10cSrcweir nIdx2++; 555cdf0e10cSrcweir } 556cdf0e10cSrcweir } while (nIdx1 < nLen1 && nIdx2 < nLen2); 557cdf0e10cSrcweir 558cdf0e10cSrcweir 559cdf0e10cSrcweir if (nDiff) 560cdf0e10cSrcweir nRes = nDiff; 561cdf0e10cSrcweir else 562cdf0e10cSrcweir { // the string with the smallest count of not ignored chars is the 563cdf0e10cSrcweir // shorter one 564cdf0e10cSrcweir 565cdf0e10cSrcweir // count remaining IgnChars 566cdf0e10cSrcweir while (nIdx1 < nLen1 ) 567cdf0e10cSrcweir { 568cdf0e10cSrcweir if (aWord1[ nIdx1++ ] == cIgnChar) 569cdf0e10cSrcweir nNumIgnChar1++; 570cdf0e10cSrcweir } 571cdf0e10cSrcweir while (nIdx2 < nLen2 ) 572cdf0e10cSrcweir { 573cdf0e10cSrcweir if (aWord2[ nIdx2++ ] == cIgnChar) 574cdf0e10cSrcweir nNumIgnChar2++; 575cdf0e10cSrcweir } 576cdf0e10cSrcweir 577cdf0e10cSrcweir nRes = ((sal_Int32) nLen1 - nNumIgnChar1) - ((sal_Int32) nLen2 - nNumIgnChar2); 578cdf0e10cSrcweir } 579cdf0e10cSrcweir 580cdf0e10cSrcweir return nRes; 581cdf0e10cSrcweir } 582cdf0e10cSrcweir 583cdf0e10cSrcweir sal_Bool DictionaryNeo::seekEntry(const OUString &rWord, 584cdf0e10cSrcweir sal_Int32 *pPos, sal_Bool bSimilarOnly) 585cdf0e10cSrcweir { 586cdf0e10cSrcweir // look for entry with binary search. 587cdf0e10cSrcweir // return sal_True if found sal_False else. 588cdf0e10cSrcweir // if pPos != NULL it will become the position of the found entry, or 589cdf0e10cSrcweir // if that was not found the position where it has to be inserted 590cdf0e10cSrcweir // to keep the entries sorted 591cdf0e10cSrcweir 592cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 593cdf0e10cSrcweir 594cdf0e10cSrcweir const uno::Reference< XDictionaryEntry > *pEntry = aEntries.getConstArray(); 595cdf0e10cSrcweir sal_Int32 nUpperIdx = getCount(), 596cdf0e10cSrcweir nMidIdx, 597cdf0e10cSrcweir nLowerIdx = 0; 598cdf0e10cSrcweir if( nUpperIdx > 0 ) 599cdf0e10cSrcweir { 600cdf0e10cSrcweir nUpperIdx--; 601cdf0e10cSrcweir while( nLowerIdx <= nUpperIdx ) 602cdf0e10cSrcweir { 603cdf0e10cSrcweir nMidIdx = (nLowerIdx + nUpperIdx) / 2; 604cdf0e10cSrcweir DBG_ASSERT(pEntry[nMidIdx].is(), "lng : empty entry encountered"); 605cdf0e10cSrcweir 606cdf0e10cSrcweir int nCmp = - cmpDicEntry( pEntry[nMidIdx]->getDictionaryWord(), 607cdf0e10cSrcweir rWord, bSimilarOnly ); 608cdf0e10cSrcweir if(nCmp == 0) 609cdf0e10cSrcweir { 610cdf0e10cSrcweir if( pPos ) *pPos = nMidIdx; 611cdf0e10cSrcweir return sal_True; 612cdf0e10cSrcweir } 613cdf0e10cSrcweir else if(nCmp > 0) 614cdf0e10cSrcweir nLowerIdx = nMidIdx + 1; 615cdf0e10cSrcweir else if( nMidIdx == 0 ) 616cdf0e10cSrcweir { 617cdf0e10cSrcweir if( pPos ) *pPos = nLowerIdx; 618cdf0e10cSrcweir return sal_False; 619cdf0e10cSrcweir } 620cdf0e10cSrcweir else 621cdf0e10cSrcweir nUpperIdx = nMidIdx - 1; 622cdf0e10cSrcweir } 623cdf0e10cSrcweir } 624cdf0e10cSrcweir if( pPos ) *pPos = nLowerIdx; 625cdf0e10cSrcweir return sal_False; 626cdf0e10cSrcweir } 627cdf0e10cSrcweir 628cdf0e10cSrcweir sal_Bool DictionaryNeo::isSorted() 629cdf0e10cSrcweir { 630cdf0e10cSrcweir sal_Bool bRes = sal_True; 631cdf0e10cSrcweir 632cdf0e10cSrcweir const uno::Reference< XDictionaryEntry > *pEntry = aEntries.getConstArray(); 633cdf0e10cSrcweir sal_Int32 nEntries = getCount(); 634cdf0e10cSrcweir sal_Int32 i; 635cdf0e10cSrcweir for (i = 1; i < nEntries; i++) 636cdf0e10cSrcweir { 637cdf0e10cSrcweir if (cmpDicEntry( pEntry[i-1]->getDictionaryWord(), 638cdf0e10cSrcweir pEntry[i]->getDictionaryWord() ) > 0) 639cdf0e10cSrcweir { 640cdf0e10cSrcweir bRes = sal_False; 641cdf0e10cSrcweir break; 642cdf0e10cSrcweir } 643cdf0e10cSrcweir } 644cdf0e10cSrcweir return bRes; 645cdf0e10cSrcweir } 646cdf0e10cSrcweir 647cdf0e10cSrcweir sal_Bool DictionaryNeo::addEntry_Impl(const uno::Reference< XDictionaryEntry > xDicEntry, 648cdf0e10cSrcweir sal_Bool bIsLoadEntries) 649cdf0e10cSrcweir { 650cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 651cdf0e10cSrcweir 652cdf0e10cSrcweir sal_Bool bRes = sal_False; 653cdf0e10cSrcweir 654cdf0e10cSrcweir if ( bIsLoadEntries || (!bIsReadonly && xDicEntry.is()) ) 655cdf0e10cSrcweir { 656cdf0e10cSrcweir sal_Bool bIsNegEntry = xDicEntry->isNegative(); 657cdf0e10cSrcweir sal_Bool bAddEntry = !isFull() && 658cdf0e10cSrcweir ( ( eDicType == DictionaryType_POSITIVE && !bIsNegEntry ) 659cdf0e10cSrcweir || ( eDicType == DictionaryType_NEGATIVE && bIsNegEntry ) 660cdf0e10cSrcweir || ( eDicType == DictionaryType_MIXED ) ); 661cdf0e10cSrcweir 662cdf0e10cSrcweir // look for position to insert entry at 663cdf0e10cSrcweir // if there is already an entry do not insert the new one 664cdf0e10cSrcweir sal_Int32 nPos = 0; 665cdf0e10cSrcweir sal_Bool bFound = sal_False; 666cdf0e10cSrcweir if (bAddEntry) 667cdf0e10cSrcweir { 668cdf0e10cSrcweir bFound = seekEntry( xDicEntry->getDictionaryWord(), &nPos ); 669cdf0e10cSrcweir if (bFound) 670cdf0e10cSrcweir bAddEntry = sal_False; 671cdf0e10cSrcweir } 672cdf0e10cSrcweir 673cdf0e10cSrcweir if (bAddEntry) 674cdf0e10cSrcweir { 675cdf0e10cSrcweir DBG_ASSERT(!bNeedEntries, "lng : entries still not loaded"); 676cdf0e10cSrcweir 677cdf0e10cSrcweir if (nCount >= aEntries.getLength()) 678cdf0e10cSrcweir aEntries.realloc( Max(2 * nCount, nCount + 32) ); 679cdf0e10cSrcweir uno::Reference< XDictionaryEntry > *pEntry = aEntries.getArray(); 680cdf0e10cSrcweir 681cdf0e10cSrcweir // shift old entries right 682cdf0e10cSrcweir sal_Int32 i; 683cdf0e10cSrcweir for (i = nCount - 1; i >= nPos; i--) 684cdf0e10cSrcweir pEntry[ i+1 ] = pEntry[ i ]; 685cdf0e10cSrcweir // insert new entry at specified position 686cdf0e10cSrcweir pEntry[ nPos ] = xDicEntry; 687cdf0e10cSrcweir DBG_ASSERT(isSorted(), "lng : dictionary entries unsorted"); 688cdf0e10cSrcweir 689cdf0e10cSrcweir nCount++; 690cdf0e10cSrcweir 691cdf0e10cSrcweir bIsModified = sal_True; 692cdf0e10cSrcweir bRes = sal_True; 693cdf0e10cSrcweir 694cdf0e10cSrcweir if (!bIsLoadEntries) 695cdf0e10cSrcweir launchEvent( DictionaryEventFlags::ADD_ENTRY, xDicEntry ); 696cdf0e10cSrcweir } 697cdf0e10cSrcweir } 698cdf0e10cSrcweir 699cdf0e10cSrcweir return bRes; 700cdf0e10cSrcweir } 701cdf0e10cSrcweir 702cdf0e10cSrcweir 703cdf0e10cSrcweir uno::Reference< XInterface > SAL_CALL DictionaryNeo_CreateInstance( 704cdf0e10cSrcweir const uno::Reference< XMultiServiceFactory > & /*rSMgr*/ ) 705cdf0e10cSrcweir throw(Exception) 706cdf0e10cSrcweir { 707cdf0e10cSrcweir uno::Reference< XInterface > xService = 708cdf0e10cSrcweir (cppu::OWeakObject*) new DictionaryNeo; 709cdf0e10cSrcweir return xService; 710cdf0e10cSrcweir } 711cdf0e10cSrcweir 712cdf0e10cSrcweir OUString SAL_CALL DictionaryNeo::getName( ) 713cdf0e10cSrcweir throw(RuntimeException) 714cdf0e10cSrcweir { 715cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 716cdf0e10cSrcweir return aDicName; 717cdf0e10cSrcweir } 718cdf0e10cSrcweir 719cdf0e10cSrcweir void SAL_CALL DictionaryNeo::setName( const OUString& aName ) 720cdf0e10cSrcweir throw(RuntimeException) 721cdf0e10cSrcweir { 722cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 723cdf0e10cSrcweir 724cdf0e10cSrcweir if (aDicName != aName) 725cdf0e10cSrcweir { 726cdf0e10cSrcweir aDicName = aName; 727cdf0e10cSrcweir launchEvent(DictionaryEventFlags::CHG_NAME, NULL); 728cdf0e10cSrcweir } 729cdf0e10cSrcweir } 730cdf0e10cSrcweir 731cdf0e10cSrcweir DictionaryType SAL_CALL DictionaryNeo::getDictionaryType( ) 732cdf0e10cSrcweir throw(RuntimeException) 733cdf0e10cSrcweir { 734cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 735cdf0e10cSrcweir 736cdf0e10cSrcweir return eDicType; 737cdf0e10cSrcweir } 738cdf0e10cSrcweir 739cdf0e10cSrcweir void SAL_CALL DictionaryNeo::setActive( sal_Bool bActivate ) 740cdf0e10cSrcweir throw(RuntimeException) 741cdf0e10cSrcweir { 742cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 743cdf0e10cSrcweir 744cdf0e10cSrcweir if (bIsActive != bActivate) 745cdf0e10cSrcweir { 746cdf0e10cSrcweir bIsActive = bActivate != 0; 747cdf0e10cSrcweir sal_Int16 nEvent = bIsActive ? 748cdf0e10cSrcweir DictionaryEventFlags::ACTIVATE_DIC : DictionaryEventFlags::DEACTIVATE_DIC; 749cdf0e10cSrcweir 750cdf0e10cSrcweir // remove entries from memory if dictionary is deactivated 751cdf0e10cSrcweir if (bIsActive == sal_False) 752cdf0e10cSrcweir { 753cdf0e10cSrcweir sal_Bool bIsEmpty = nCount == 0; 754cdf0e10cSrcweir 755cdf0e10cSrcweir // save entries first if necessary 756cdf0e10cSrcweir if (bIsModified && hasLocation() && !isReadonly()) 757cdf0e10cSrcweir { 758cdf0e10cSrcweir store(); 759cdf0e10cSrcweir 760cdf0e10cSrcweir aEntries.realloc( 0 ); 761cdf0e10cSrcweir nCount = 0; 762cdf0e10cSrcweir bNeedEntries = !bIsEmpty; 763cdf0e10cSrcweir } 764cdf0e10cSrcweir DBG_ASSERT( !bIsModified || !hasLocation() || isReadonly(), 765cdf0e10cSrcweir "lng : dictionary is still modified" ); 766cdf0e10cSrcweir } 767cdf0e10cSrcweir 768cdf0e10cSrcweir launchEvent(nEvent, NULL); 769cdf0e10cSrcweir } 770cdf0e10cSrcweir } 771cdf0e10cSrcweir 772cdf0e10cSrcweir sal_Bool SAL_CALL DictionaryNeo::isActive( ) 773cdf0e10cSrcweir throw(RuntimeException) 774cdf0e10cSrcweir { 775cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 776cdf0e10cSrcweir return bIsActive; 777cdf0e10cSrcweir } 778cdf0e10cSrcweir 779cdf0e10cSrcweir sal_Int32 SAL_CALL DictionaryNeo::getCount( ) 780cdf0e10cSrcweir throw(RuntimeException) 781cdf0e10cSrcweir { 782cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 783cdf0e10cSrcweir 784cdf0e10cSrcweir if (bNeedEntries) 785cdf0e10cSrcweir loadEntries( aMainURL ); 786cdf0e10cSrcweir return nCount; 787cdf0e10cSrcweir } 788cdf0e10cSrcweir 789cdf0e10cSrcweir Locale SAL_CALL DictionaryNeo::getLocale( ) 790cdf0e10cSrcweir throw(RuntimeException) 791cdf0e10cSrcweir { 792cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 793cdf0e10cSrcweir Locale aRes; 794cdf0e10cSrcweir return LanguageToLocale( aRes, nLanguage ); 795cdf0e10cSrcweir } 796cdf0e10cSrcweir 797cdf0e10cSrcweir void SAL_CALL DictionaryNeo::setLocale( const Locale& aLocale ) 798cdf0e10cSrcweir throw(RuntimeException) 799cdf0e10cSrcweir { 800cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 801cdf0e10cSrcweir sal_Int16 nLanguageP = LocaleToLanguage( aLocale ); 802cdf0e10cSrcweir if (!bIsReadonly && nLanguage != nLanguageP) 803cdf0e10cSrcweir { 804cdf0e10cSrcweir nLanguage = nLanguageP; 805cdf0e10cSrcweir bIsModified = sal_True; // new language needs to be saved with dictionary 806cdf0e10cSrcweir 807cdf0e10cSrcweir launchEvent( DictionaryEventFlags::CHG_LANGUAGE, NULL ); 808cdf0e10cSrcweir } 809cdf0e10cSrcweir } 810cdf0e10cSrcweir 811cdf0e10cSrcweir uno::Reference< XDictionaryEntry > SAL_CALL DictionaryNeo::getEntry( 812cdf0e10cSrcweir const OUString& aWord ) 813cdf0e10cSrcweir throw(RuntimeException) 814cdf0e10cSrcweir { 815cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 816cdf0e10cSrcweir 817cdf0e10cSrcweir if (bNeedEntries) 818cdf0e10cSrcweir loadEntries( aMainURL ); 819cdf0e10cSrcweir 820cdf0e10cSrcweir sal_Int32 nPos; 821cdf0e10cSrcweir sal_Bool bFound = seekEntry( aWord, &nPos, sal_True ); 822cdf0e10cSrcweir DBG_ASSERT( nCount <= aEntries.getLength(), "lng : wrong number of entries"); 823cdf0e10cSrcweir DBG_ASSERT(!bFound || nPos < nCount, "lng : index out of range"); 824cdf0e10cSrcweir 825cdf0e10cSrcweir return bFound ? aEntries.getConstArray()[ nPos ] 826cdf0e10cSrcweir : uno::Reference< XDictionaryEntry >(); 827cdf0e10cSrcweir } 828cdf0e10cSrcweir 829cdf0e10cSrcweir sal_Bool SAL_CALL DictionaryNeo::addEntry( 830cdf0e10cSrcweir const uno::Reference< XDictionaryEntry >& xDicEntry ) 831cdf0e10cSrcweir throw(RuntimeException) 832cdf0e10cSrcweir { 833cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 834cdf0e10cSrcweir 835cdf0e10cSrcweir sal_Bool bRes = sal_False; 836cdf0e10cSrcweir 837cdf0e10cSrcweir if (!bIsReadonly) 838cdf0e10cSrcweir { 839cdf0e10cSrcweir if (bNeedEntries) 840cdf0e10cSrcweir loadEntries( aMainURL ); 841cdf0e10cSrcweir bRes = addEntry_Impl( xDicEntry ); 842cdf0e10cSrcweir } 843cdf0e10cSrcweir 844cdf0e10cSrcweir return bRes; 845cdf0e10cSrcweir } 846cdf0e10cSrcweir 847cdf0e10cSrcweir sal_Bool SAL_CALL 848cdf0e10cSrcweir DictionaryNeo::add( const OUString& rWord, sal_Bool bIsNegative, 849cdf0e10cSrcweir const OUString& rRplcText ) 850cdf0e10cSrcweir throw(RuntimeException) 851cdf0e10cSrcweir { 852cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 853cdf0e10cSrcweir 854cdf0e10cSrcweir sal_Bool bRes = sal_False; 855cdf0e10cSrcweir 856cdf0e10cSrcweir if (!bIsReadonly) 857cdf0e10cSrcweir { 858cdf0e10cSrcweir uno::Reference< XDictionaryEntry > xEntry = 859cdf0e10cSrcweir new DicEntry( rWord, bIsNegative, rRplcText ); 860cdf0e10cSrcweir bRes = addEntry_Impl( xEntry ); 861cdf0e10cSrcweir } 862cdf0e10cSrcweir 863cdf0e10cSrcweir return bRes; 864cdf0e10cSrcweir } 865cdf0e10cSrcweir 866cdf0e10cSrcweir void lcl_SequenceRemoveElementAt( 867cdf0e10cSrcweir uno::Sequence< uno::Reference< XDictionaryEntry > >& rEntries, int nPos ) 868cdf0e10cSrcweir { 869cdf0e10cSrcweir //TODO: helper for SequenceRemoveElementAt available? 870cdf0e10cSrcweir if(nPos >= rEntries.getLength()) 871cdf0e10cSrcweir return; 872cdf0e10cSrcweir uno::Sequence< uno::Reference< XDictionaryEntry > > aTmp(rEntries.getLength() - 1); 873cdf0e10cSrcweir uno::Reference< XDictionaryEntry > * pOrig = rEntries.getArray(); 874cdf0e10cSrcweir uno::Reference< XDictionaryEntry > * pTemp = aTmp.getArray(); 875cdf0e10cSrcweir int nOffset = 0; 876cdf0e10cSrcweir for(int i = 0; i < aTmp.getLength(); i++) 877cdf0e10cSrcweir { 878cdf0e10cSrcweir if(nPos == i) 879cdf0e10cSrcweir nOffset++; 880cdf0e10cSrcweir pTemp[i] = pOrig[i + nOffset]; 881cdf0e10cSrcweir } 882cdf0e10cSrcweir 883cdf0e10cSrcweir rEntries = aTmp; 884cdf0e10cSrcweir } 885cdf0e10cSrcweir 886cdf0e10cSrcweir sal_Bool SAL_CALL DictionaryNeo::remove( const OUString& aWord ) 887cdf0e10cSrcweir throw(RuntimeException) 888cdf0e10cSrcweir { 889cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 890cdf0e10cSrcweir 891cdf0e10cSrcweir sal_Bool bRemoved = sal_False; 892cdf0e10cSrcweir 893cdf0e10cSrcweir if (!bIsReadonly) 894cdf0e10cSrcweir { 895cdf0e10cSrcweir if (bNeedEntries) 896cdf0e10cSrcweir loadEntries( aMainURL ); 897cdf0e10cSrcweir 898cdf0e10cSrcweir sal_Int32 nPos; 899cdf0e10cSrcweir sal_Bool bFound = seekEntry( aWord, &nPos ); 900cdf0e10cSrcweir DBG_ASSERT( nCount < aEntries.getLength(), 901cdf0e10cSrcweir "lng : wrong number of entries"); 902cdf0e10cSrcweir DBG_ASSERT(!bFound || nPos < nCount, "lng : index out of range"); 903cdf0e10cSrcweir 904cdf0e10cSrcweir // remove element if found 905cdf0e10cSrcweir if (bFound) 906cdf0e10cSrcweir { 907cdf0e10cSrcweir // entry to be removed 908cdf0e10cSrcweir uno::Reference< XDictionaryEntry > 909cdf0e10cSrcweir xDicEntry( aEntries.getConstArray()[ nPos ] ); 910cdf0e10cSrcweir DBG_ASSERT(xDicEntry.is(), "lng : dictionary entry is NULL"); 911cdf0e10cSrcweir 912cdf0e10cSrcweir nCount--; 913cdf0e10cSrcweir 914cdf0e10cSrcweir //! the following call reduces the length of the sequence by 1 also 915cdf0e10cSrcweir lcl_SequenceRemoveElementAt( aEntries, nPos ); 916cdf0e10cSrcweir bRemoved = bIsModified = sal_True; 917cdf0e10cSrcweir 918cdf0e10cSrcweir launchEvent( DictionaryEventFlags::DEL_ENTRY, xDicEntry ); 919cdf0e10cSrcweir } 920cdf0e10cSrcweir } 921cdf0e10cSrcweir 922cdf0e10cSrcweir return bRemoved; 923cdf0e10cSrcweir } 924cdf0e10cSrcweir 925cdf0e10cSrcweir sal_Bool SAL_CALL DictionaryNeo::isFull( ) 926cdf0e10cSrcweir throw(RuntimeException) 927cdf0e10cSrcweir { 928cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 929cdf0e10cSrcweir 930cdf0e10cSrcweir if (bNeedEntries) 931cdf0e10cSrcweir loadEntries( aMainURL ); 932cdf0e10cSrcweir return nCount >= DIC_MAX_ENTRIES; 933cdf0e10cSrcweir } 934cdf0e10cSrcweir 935cdf0e10cSrcweir uno::Sequence< uno::Reference< XDictionaryEntry > > 936cdf0e10cSrcweir SAL_CALL DictionaryNeo::getEntries( ) 937cdf0e10cSrcweir throw(RuntimeException) 938cdf0e10cSrcweir { 939cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 940cdf0e10cSrcweir 941cdf0e10cSrcweir if (bNeedEntries) 942cdf0e10cSrcweir loadEntries( aMainURL ); 943cdf0e10cSrcweir //! return sequence with length equal to the number of dictionary entries 944cdf0e10cSrcweir //! (internal used sequence may have additional unused elements.) 945cdf0e10cSrcweir return uno::Sequence< uno::Reference< XDictionaryEntry > > 946cdf0e10cSrcweir (aEntries.getConstArray(), nCount); 947cdf0e10cSrcweir } 948cdf0e10cSrcweir 949cdf0e10cSrcweir 950cdf0e10cSrcweir void SAL_CALL DictionaryNeo::clear( ) 951cdf0e10cSrcweir throw(RuntimeException) 952cdf0e10cSrcweir { 953cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 954cdf0e10cSrcweir 955cdf0e10cSrcweir if (!bIsReadonly && nCount) 956cdf0e10cSrcweir { 957cdf0e10cSrcweir // release all references to old entries and provide space for new ones 958cdf0e10cSrcweir aEntries = uno::Sequence< uno::Reference< XDictionaryEntry > > ( 32 ); 959cdf0e10cSrcweir 960cdf0e10cSrcweir nCount = 0; 961cdf0e10cSrcweir bNeedEntries = sal_False; 962cdf0e10cSrcweir bIsModified = sal_True; 963cdf0e10cSrcweir 964cdf0e10cSrcweir launchEvent( DictionaryEventFlags::ENTRIES_CLEARED , NULL ); 965cdf0e10cSrcweir } 966cdf0e10cSrcweir } 967cdf0e10cSrcweir 968cdf0e10cSrcweir sal_Bool SAL_CALL DictionaryNeo::addDictionaryEventListener( 969cdf0e10cSrcweir const uno::Reference< XDictionaryEventListener >& xListener ) 970cdf0e10cSrcweir throw(RuntimeException) 971cdf0e10cSrcweir { 972cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 973cdf0e10cSrcweir 974cdf0e10cSrcweir sal_Bool bRes = sal_False; 975cdf0e10cSrcweir if (xListener.is()) 976cdf0e10cSrcweir { 977cdf0e10cSrcweir sal_Int32 nLen = aDicEvtListeners.getLength(); 978cdf0e10cSrcweir bRes = aDicEvtListeners.addInterface( xListener ) != nLen; 979cdf0e10cSrcweir } 980cdf0e10cSrcweir return bRes; 981cdf0e10cSrcweir } 982cdf0e10cSrcweir 983cdf0e10cSrcweir sal_Bool SAL_CALL DictionaryNeo::removeDictionaryEventListener( 984cdf0e10cSrcweir const uno::Reference< XDictionaryEventListener >& xListener ) 985cdf0e10cSrcweir throw(RuntimeException) 986cdf0e10cSrcweir { 987cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 988cdf0e10cSrcweir 989cdf0e10cSrcweir sal_Bool bRes = sal_False; 990cdf0e10cSrcweir if (xListener.is()) 991cdf0e10cSrcweir { 992cdf0e10cSrcweir sal_Int32 nLen = aDicEvtListeners.getLength(); 993cdf0e10cSrcweir bRes = aDicEvtListeners.removeInterface( xListener ) != nLen; 994cdf0e10cSrcweir } 995cdf0e10cSrcweir return bRes; 996cdf0e10cSrcweir } 997cdf0e10cSrcweir 998cdf0e10cSrcweir 999cdf0e10cSrcweir sal_Bool SAL_CALL DictionaryNeo::hasLocation() 1000cdf0e10cSrcweir throw(RuntimeException) 1001cdf0e10cSrcweir { 1002cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 1003cdf0e10cSrcweir return aMainURL.getLength() > 0; 1004cdf0e10cSrcweir } 1005cdf0e10cSrcweir 1006cdf0e10cSrcweir OUString SAL_CALL DictionaryNeo::getLocation() 1007cdf0e10cSrcweir throw(RuntimeException) 1008cdf0e10cSrcweir { 1009cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 1010cdf0e10cSrcweir return aMainURL; 1011cdf0e10cSrcweir } 1012cdf0e10cSrcweir 1013cdf0e10cSrcweir sal_Bool SAL_CALL DictionaryNeo::isReadonly() 1014cdf0e10cSrcweir throw(RuntimeException) 1015cdf0e10cSrcweir { 1016cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 1017cdf0e10cSrcweir 1018cdf0e10cSrcweir return bIsReadonly; 1019cdf0e10cSrcweir } 1020cdf0e10cSrcweir 1021cdf0e10cSrcweir void SAL_CALL DictionaryNeo::store() 1022cdf0e10cSrcweir throw(io::IOException, RuntimeException) 1023cdf0e10cSrcweir { 1024cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 1025cdf0e10cSrcweir 1026cdf0e10cSrcweir if (bIsModified && hasLocation() && !isReadonly()) 1027cdf0e10cSrcweir { 1028cdf0e10cSrcweir if (saveEntries( aMainURL )) 1029cdf0e10cSrcweir { 1030cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS 1031cdf0e10cSrcweir throw io::IOException(); 1032cdf0e10cSrcweir #endif 1033cdf0e10cSrcweir } 1034cdf0e10cSrcweir else 1035cdf0e10cSrcweir bIsModified = sal_False; 1036cdf0e10cSrcweir } 1037cdf0e10cSrcweir } 1038cdf0e10cSrcweir 1039cdf0e10cSrcweir void SAL_CALL DictionaryNeo::storeAsURL( 1040cdf0e10cSrcweir const OUString& aURL, 1041cdf0e10cSrcweir const uno::Sequence< beans::PropertyValue >& /*rArgs*/ ) 1042cdf0e10cSrcweir throw(io::IOException, RuntimeException) 1043cdf0e10cSrcweir { 1044cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 1045cdf0e10cSrcweir 1046cdf0e10cSrcweir if (saveEntries( aURL )) 1047cdf0e10cSrcweir { 1048cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS 1049cdf0e10cSrcweir throw io::IOException(); 1050cdf0e10cSrcweir #endif 1051cdf0e10cSrcweir } 1052cdf0e10cSrcweir else 1053cdf0e10cSrcweir { 1054cdf0e10cSrcweir aMainURL = aURL; 1055cdf0e10cSrcweir bIsModified = sal_False; 1056cdf0e10cSrcweir bIsReadonly = IsReadOnly( getLocation() ); 1057cdf0e10cSrcweir } 1058cdf0e10cSrcweir } 1059cdf0e10cSrcweir 1060cdf0e10cSrcweir void SAL_CALL DictionaryNeo::storeToURL( 1061cdf0e10cSrcweir const OUString& aURL, 1062cdf0e10cSrcweir const uno::Sequence< beans::PropertyValue >& /*rArgs*/ ) 1063cdf0e10cSrcweir throw(io::IOException, RuntimeException) 1064cdf0e10cSrcweir { 1065cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 1066cdf0e10cSrcweir 1067cdf0e10cSrcweir if (saveEntries( aURL )) 1068cdf0e10cSrcweir { 1069cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS 1070cdf0e10cSrcweir throw io::IOException(); 1071cdf0e10cSrcweir #endif 1072cdf0e10cSrcweir } 1073cdf0e10cSrcweir } 1074cdf0e10cSrcweir 1075cdf0e10cSrcweir /////////////////////////////////////////////////////////////////////////// 1076cdf0e10cSrcweir 1077cdf0e10cSrcweir DicEntry::DicEntry() 1078cdf0e10cSrcweir { 1079cdf0e10cSrcweir bIsNegativ = sal_False; 1080cdf0e10cSrcweir } 1081cdf0e10cSrcweir 1082cdf0e10cSrcweir DicEntry::DicEntry(const OUString &rDicFileWord, 1083cdf0e10cSrcweir sal_Bool bIsNegativWord) 1084cdf0e10cSrcweir { 1085cdf0e10cSrcweir if (rDicFileWord.getLength()) 1086cdf0e10cSrcweir splitDicFileWord( rDicFileWord, aDicWord, aReplacement ); 1087cdf0e10cSrcweir bIsNegativ = bIsNegativWord; 1088cdf0e10cSrcweir } 1089cdf0e10cSrcweir 1090cdf0e10cSrcweir DicEntry::DicEntry(const OUString &rDicWord, sal_Bool bNegativ, 1091cdf0e10cSrcweir const OUString &rRplcText) : 1092cdf0e10cSrcweir aDicWord (rDicWord), 1093cdf0e10cSrcweir aReplacement (rRplcText), 1094cdf0e10cSrcweir bIsNegativ (bNegativ) 1095cdf0e10cSrcweir { 1096cdf0e10cSrcweir } 1097cdf0e10cSrcweir 1098cdf0e10cSrcweir DicEntry::~DicEntry() 1099cdf0e10cSrcweir { 1100cdf0e10cSrcweir } 1101cdf0e10cSrcweir 1102cdf0e10cSrcweir void DicEntry::splitDicFileWord(const OUString &rDicFileWord, 1103cdf0e10cSrcweir OUString &rDicWord, 1104cdf0e10cSrcweir OUString &rReplacement) 1105cdf0e10cSrcweir { 1106cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 1107cdf0e10cSrcweir 1108cdf0e10cSrcweir static const OUString aDelim( A2OU( "==" ) ); 1109cdf0e10cSrcweir 1110cdf0e10cSrcweir sal_Int32 nDelimPos = rDicFileWord.indexOf( aDelim ); 1111cdf0e10cSrcweir if (-1 != nDelimPos) 1112cdf0e10cSrcweir { 1113cdf0e10cSrcweir sal_Int32 nTriplePos = nDelimPos + 2; 1114cdf0e10cSrcweir if ( nTriplePos < rDicFileWord.getLength() 1115cdf0e10cSrcweir && rDicFileWord[ nTriplePos ] == '=' ) 1116cdf0e10cSrcweir ++nDelimPos; 1117cdf0e10cSrcweir rDicWord = rDicFileWord.copy( 0, nDelimPos ); 1118cdf0e10cSrcweir rReplacement = rDicFileWord.copy( nDelimPos + 2 ); 1119cdf0e10cSrcweir } 1120cdf0e10cSrcweir else 1121cdf0e10cSrcweir { 1122cdf0e10cSrcweir rDicWord = rDicFileWord; 1123cdf0e10cSrcweir rReplacement = OUString(); 1124cdf0e10cSrcweir } 1125cdf0e10cSrcweir } 1126cdf0e10cSrcweir 1127cdf0e10cSrcweir OUString SAL_CALL DicEntry::getDictionaryWord( ) 1128cdf0e10cSrcweir throw(RuntimeException) 1129cdf0e10cSrcweir { 1130cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 1131cdf0e10cSrcweir return aDicWord; 1132cdf0e10cSrcweir } 1133cdf0e10cSrcweir 1134cdf0e10cSrcweir sal_Bool SAL_CALL DicEntry::isNegative( ) 1135cdf0e10cSrcweir throw(RuntimeException) 1136cdf0e10cSrcweir { 1137cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 1138cdf0e10cSrcweir return bIsNegativ; 1139cdf0e10cSrcweir } 1140cdf0e10cSrcweir 1141cdf0e10cSrcweir OUString SAL_CALL DicEntry::getReplacementText( ) 1142cdf0e10cSrcweir throw(RuntimeException) 1143cdf0e10cSrcweir { 1144cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 1145cdf0e10cSrcweir return aReplacement; 1146cdf0e10cSrcweir } 1147cdf0e10cSrcweir 1148cdf0e10cSrcweir 1149cdf0e10cSrcweir /////////////////////////////////////////////////////////////////////////// 1150cdf0e10cSrcweir 1151