add Santali (Ol-Chiki) languagepack (sat-Olck)
[LibreOffice.git] / linguistic / source / dlistimp.cxx
blobdd436233de04c9ff75dd042fda1d01076c409acd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <cppuhelper/factory.hxx>
22 #include <osl/file.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/stream.hxx>
25 #include <tools/urlobj.hxx>
26 #include <unotools/useroptions.hxx>
27 #include <cppuhelper/supportsservice.hxx>
28 #include <cppuhelper/weak.hxx>
29 #include <unotools/localfilehelper.hxx>
30 #include <comphelper/lok.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/sequence.hxx>
33 #include <unotools/ucbstreamhelper.hxx>
34 #include <com/sun/star/frame/XStorable.hpp>
35 #include <com/sun/star/uno/Reference.h>
36 #include <com/sun/star/linguistic2/DictionaryEventFlags.hpp>
37 #include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
38 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
39 #include <svtools/strings.hrc>
40 #include <unotools/resmgr.hxx>
41 #include <unotools/charclass.hxx>
42 #include <sal/log.hxx>
43 #include <utility>
45 #include "dlistimp.hxx"
46 #include "dicimp.hxx"
47 #include "lngopt.hxx"
49 using namespace osl;
50 using namespace com::sun::star;
51 using namespace com::sun::star::lang;
52 using namespace com::sun::star::uno;
53 using namespace com::sun::star::linguistic2;
54 using namespace linguistic;
57 static bool IsVers2OrNewer( const OUString& rFileURL, LanguageType& nLng, bool& bNeg, OUString& aDicName );
59 static void AddInternal( const uno::Reference< XDictionary > &rDic,
60 const OUString& rNew );
61 static void AddUserData( const uno::Reference< XDictionary > &rDic );
64 class DicEvtListenerHelper :
65 public cppu::WeakImplHelper
67 XDictionaryEventListener
70 comphelper::OInterfaceContainerHelper3<XDictionaryListEventListener> aDicListEvtListeners;
71 uno::Reference< XDictionaryList > xMyDicList;
73 sal_Int16 nCondensedEvt;
74 sal_Int16 nNumCollectEvtListeners;
76 public:
77 explicit DicEvtListenerHelper( uno::Reference< XDictionaryList > xDicList );
78 virtual ~DicEvtListenerHelper() override;
80 // XEventListener
81 virtual void SAL_CALL
82 disposing( const EventObject& rSource ) override;
84 // XDictionaryEventListener
85 virtual void SAL_CALL
86 processDictionaryEvent( const DictionaryEvent& rDicEvent ) override;
88 // non-UNO functions
89 void DisposeAndClear( const EventObject &rEvtObj );
91 bool AddDicListEvtListener(
92 const uno::Reference< XDictionaryListEventListener >& rxListener );
93 bool RemoveDicListEvtListener(
94 const uno::Reference< XDictionaryListEventListener >& rxListener );
95 sal_Int16 BeginCollectEvents() { return ++nNumCollectEvtListeners;}
96 sal_Int16 EndCollectEvents();
97 sal_Int16 FlushEvents();
98 void ClearEvents() { nCondensedEvt = 0; }
102 DicEvtListenerHelper::DicEvtListenerHelper(
103 uno::Reference< XDictionaryList > xDicList ) :
104 aDicListEvtListeners ( GetLinguMutex() ),
105 xMyDicList (std::move( xDicList )),
106 nCondensedEvt(0), nNumCollectEvtListeners(0)
111 DicEvtListenerHelper::~DicEvtListenerHelper()
113 DBG_ASSERT(aDicListEvtListeners.getLength() == 0,
114 "lng : event listeners are still existing");
118 void DicEvtListenerHelper::DisposeAndClear( const EventObject &rEvtObj )
120 aDicListEvtListeners.disposeAndClear( rEvtObj );
124 void SAL_CALL DicEvtListenerHelper::disposing( const EventObject& rSource )
126 osl::MutexGuard aGuard( GetLinguMutex() );
128 uno::Reference< XDictionaryListEventListener > xSrc( rSource.Source, UNO_QUERY );
130 // remove event object from EventListener list
131 if (xSrc.is())
132 aDicListEvtListeners.removeInterface( xSrc );
134 // if object is a dictionary then remove it from the dictionary list
135 // Note: this will probably happen only if someone makes a XDictionary
136 // implementation of his own that is also a XComponent.
137 uno::Reference< XDictionary > xDic( rSource.Source, UNO_QUERY );
138 if (xDic.is())
140 xMyDicList->removeDictionary( xDic );
145 void SAL_CALL DicEvtListenerHelper::processDictionaryEvent(
146 const DictionaryEvent& rDicEvent )
148 osl::MutexGuard aGuard( GetLinguMutex() );
150 uno::Reference< XDictionary > xDic( rDicEvent.Source, UNO_QUERY );
151 DBG_ASSERT(xDic.is(), "lng : missing event source");
153 // assert that there is a corresponding dictionary entry if one was
154 // added or deleted
155 DBG_ASSERT( !(rDicEvent.nEvent &
156 (DictionaryEventFlags::ADD_ENTRY | DictionaryEventFlags::DEL_ENTRY))
157 || rDicEvent.xDictionaryEntry.is(),
158 "lng : missing dictionary entry" );
160 // evaluate DictionaryEvents and update data for next DictionaryListEvent
161 DictionaryType eDicType = xDic->getDictionaryType();
162 DBG_ASSERT(eDicType != DictionaryType_MIXED,
163 "lng : unexpected dictionary type");
164 if ((rDicEvent.nEvent & DictionaryEventFlags::ADD_ENTRY) && xDic->isActive())
165 nCondensedEvt |= rDicEvent.xDictionaryEntry->isNegative() ?
166 DictionaryListEventFlags::ADD_NEG_ENTRY :
167 DictionaryListEventFlags::ADD_POS_ENTRY;
168 if ((rDicEvent.nEvent & DictionaryEventFlags::DEL_ENTRY) && xDic->isActive())
169 nCondensedEvt |= rDicEvent.xDictionaryEntry->isNegative() ?
170 DictionaryListEventFlags::DEL_NEG_ENTRY :
171 DictionaryListEventFlags::DEL_POS_ENTRY;
172 if ((rDicEvent.nEvent & DictionaryEventFlags::ENTRIES_CLEARED) && xDic->isActive())
173 nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
174 DictionaryListEventFlags::DEL_NEG_ENTRY :
175 DictionaryListEventFlags::DEL_POS_ENTRY;
176 if ((rDicEvent.nEvent & DictionaryEventFlags::CHG_LANGUAGE) && xDic->isActive())
177 nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
178 DictionaryListEventFlags::DEACTIVATE_NEG_DIC
179 | DictionaryListEventFlags::ACTIVATE_NEG_DIC :
180 DictionaryListEventFlags::DEACTIVATE_POS_DIC
181 | DictionaryListEventFlags::ACTIVATE_POS_DIC;
182 if (rDicEvent.nEvent & DictionaryEventFlags::ACTIVATE_DIC)
183 nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
184 DictionaryListEventFlags::ACTIVATE_NEG_DIC :
185 DictionaryListEventFlags::ACTIVATE_POS_DIC;
186 if (rDicEvent.nEvent & DictionaryEventFlags::DEACTIVATE_DIC)
187 nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
188 DictionaryListEventFlags::DEACTIVATE_NEG_DIC :
189 DictionaryListEventFlags::DEACTIVATE_POS_DIC;
191 if (nNumCollectEvtListeners == 0 && nCondensedEvt != 0)
192 FlushEvents();
196 bool DicEvtListenerHelper::AddDicListEvtListener(
197 const uno::Reference< XDictionaryListEventListener >& xListener )
199 DBG_ASSERT( xListener.is(), "empty reference" );
200 sal_Int32 nCount = aDicListEvtListeners.getLength();
201 return aDicListEvtListeners.addInterface( xListener ) != nCount;
205 bool DicEvtListenerHelper::RemoveDicListEvtListener(
206 const uno::Reference< XDictionaryListEventListener >& xListener )
208 DBG_ASSERT( xListener.is(), "empty reference" );
209 sal_Int32 nCount = aDicListEvtListeners.getLength();
210 return aDicListEvtListeners.removeInterface( xListener ) != nCount;
214 sal_Int16 DicEvtListenerHelper::EndCollectEvents()
216 DBG_ASSERT(nNumCollectEvtListeners > 0, "lng: mismatched function call");
217 if (nNumCollectEvtListeners > 0)
219 FlushEvents();
220 nNumCollectEvtListeners--;
223 return nNumCollectEvtListeners;
227 sal_Int16 DicEvtListenerHelper::FlushEvents()
229 if (0 != nCondensedEvt)
231 // build DictionaryListEvent to pass on to listeners
232 uno::Sequence< DictionaryEvent > aDicEvents;
233 DictionaryListEvent aEvent( xMyDicList, nCondensedEvt, aDicEvents );
235 // pass on event
236 aDicListEvtListeners.notifyEach( &XDictionaryListEventListener::processDictionaryListEvent, aEvent );
238 // clear "list" of events
239 nCondensedEvt = 0;
242 return nNumCollectEvtListeners;
246 void DicList::MyAppExitListener::AtExit()
248 rMyDicList.SaveDics();
252 DicList::DicList() :
253 aEvtListeners ( GetLinguMutex() )
255 mxDicEvtLstnrHelper = new DicEvtListenerHelper( this );
256 bDisposing = false;
257 bInCreation = false;
259 mxExitListener = new MyAppExitListener( *this );
260 mxExitListener->Activate();
263 DicList::~DicList()
265 mxExitListener->Deactivate();
269 void DicList::SearchForDictionaries(
270 DictionaryVec_t&rDicList,
271 const OUString &rDicDirURL,
272 bool bIsWriteablePath )
274 osl::MutexGuard aGuard( GetLinguMutex() );
276 const uno::Sequence< OUString > aDirCnt( utl::LocalFileHelper::
277 GetFolderContents( rDicDirURL, false ) );
278 SvtSysLocale aSysLocale;
280 for (const OUString& aURL : aDirCnt)
282 LanguageType nLang = LANGUAGE_NONE;
283 bool bNeg = false;
284 OUString aDicTitle = u""_ustr;
286 if(!::IsVers2OrNewer( aURL, nLang, bNeg, aDicTitle ))
288 // When not
289 sal_Int32 nPos = aURL.indexOf('.');
290 OUString aExt( aURL.copy(nPos + 1).toAsciiLowerCase() );
292 if ("dcn" == aExt) // negative
293 bNeg = true;
294 else if ("dcp" == aExt) // positive
295 bNeg = false;
296 else
297 continue; // other files
300 // Record in the list of Dictionaries
301 // When it already exists don't record
302 OUString aTmp1 = aSysLocale.GetCharClass().lowercase( aURL);
303 sal_Int32 nPos = aTmp1.lastIndexOf( '/' );
304 if (-1 != nPos)
305 aTmp1 = aTmp1.copy( nPos + 1 );
306 OUString aTmp2;
307 size_t j;
308 size_t nCount = rDicList.size();
309 for(j = 0; j < nCount; j++)
311 aTmp2 = rDicList[j]->getName();
312 aTmp2 = aSysLocale.GetCharClass().lowercase( aTmp2);
313 if(aTmp1 == aTmp2)
314 break;
316 if(j >= nCount) // dictionary not yet in DicList
318 // get decoded dictionary file name
319 INetURLObject aURLObj( aURL );
320 OUString aDicName = aURLObj.getName( INetURLObject::LAST_SEGMENT,
321 true, INetURLObject::DecodeMechanism::WithCharset );
323 DictionaryType eType = bNeg ? DictionaryType_NEGATIVE : DictionaryType_POSITIVE;
324 uno::Reference< XDictionary > xDic =
325 new DictionaryNeo( aDicTitle.isEmpty() ? aDicName : aDicTitle, nLang, eType, aURL, bIsWriteablePath );
327 addDictionary( xDic );
328 nCount++;
334 sal_Int32 DicList::GetDicPos(const uno::Reference< XDictionary > &xDic)
336 osl::MutexGuard aGuard( GetLinguMutex() );
338 DictionaryVec_t& rDicList = GetOrCreateDicList();
339 size_t n = rDicList.size();
340 for (size_t i = 0; i < n; i++)
342 if ( rDicList[i] == xDic )
343 return i;
345 return -1;
348 sal_Int16 SAL_CALL DicList::getCount()
350 osl::MutexGuard aGuard( GetLinguMutex() );
351 return static_cast< sal_Int16 >(GetOrCreateDicList().size());
354 uno::Sequence< uno::Reference< XDictionary > > SAL_CALL
355 DicList::getDictionaries()
357 osl::MutexGuard aGuard( GetLinguMutex() );
359 DictionaryVec_t& rDicList = GetOrCreateDicList();
361 return comphelper::containerToSequence(rDicList);
364 uno::Reference< XDictionary > SAL_CALL
365 DicList::getDictionaryByName( const OUString& aDictionaryName )
367 osl::MutexGuard aGuard( GetLinguMutex() );
369 uno::Reference< XDictionary > xDic;
370 DictionaryVec_t& rDicList = GetOrCreateDicList();
371 size_t nCount = rDicList.size();
372 for (size_t i = 0; i < nCount; i++)
374 const uno::Reference< XDictionary > &rDic = rDicList[i];
375 if (rDic.is() && rDic->getName() == aDictionaryName)
377 xDic = rDic;
378 break;
382 return xDic;
385 sal_Bool SAL_CALL DicList::addDictionary(
386 const uno::Reference< XDictionary >& xDictionary )
388 osl::MutexGuard aGuard( GetLinguMutex() );
390 if (bDisposing)
391 return false;
393 bool bRes = false;
394 if (xDictionary.is())
396 DictionaryVec_t& rDicList = GetOrCreateDicList();
397 rDicList.push_back( xDictionary );
398 bRes = true;
400 // add listener helper to the dictionaries listener lists
401 xDictionary->addDictionaryEventListener( mxDicEvtLstnrHelper );
403 return bRes;
406 sal_Bool SAL_CALL
407 DicList::removeDictionary( const uno::Reference< XDictionary >& xDictionary )
409 osl::MutexGuard aGuard( GetLinguMutex() );
411 if (bDisposing)
412 return false;
414 bool bRes = false;
415 sal_Int32 nPos = GetDicPos( xDictionary );
416 if (nPos >= 0)
418 // remove dictionary list from the dictionaries listener lists
419 DictionaryVec_t& rDicList = GetOrCreateDicList();
420 uno::Reference< XDictionary > xDic( rDicList[ nPos ] );
421 DBG_ASSERT(xDic.is(), "lng : empty reference");
422 if (xDic.is())
424 // deactivate dictionary if not already done
425 xDic->setActive( false );
427 xDic->removeDictionaryEventListener( mxDicEvtLstnrHelper );
430 // remove element at nPos
431 rDicList.erase( rDicList.begin() + nPos );
432 bRes = true;
434 return bRes;
437 sal_Bool SAL_CALL DicList::addDictionaryListEventListener(
438 const uno::Reference< XDictionaryListEventListener >& xListener,
439 sal_Bool bReceiveVerbose )
441 osl::MutexGuard aGuard( GetLinguMutex() );
443 if (bDisposing)
444 return false;
446 DBG_ASSERT(!bReceiveVerbose, "lng : not yet supported");
448 bool bRes = false;
449 if (xListener.is()) //! don't add empty references
451 bRes = mxDicEvtLstnrHelper->AddDicListEvtListener( xListener );
453 return bRes;
456 sal_Bool SAL_CALL DicList::removeDictionaryListEventListener(
457 const uno::Reference< XDictionaryListEventListener >& xListener )
459 osl::MutexGuard aGuard( GetLinguMutex() );
461 if (bDisposing)
462 return false;
464 bool bRes = false;
465 if(xListener.is())
467 bRes = mxDicEvtLstnrHelper->RemoveDicListEvtListener( xListener );
469 return bRes;
472 sal_Int16 SAL_CALL DicList::beginCollectEvents()
474 osl::MutexGuard aGuard( GetLinguMutex() );
475 return mxDicEvtLstnrHelper->BeginCollectEvents();
478 sal_Int16 SAL_CALL DicList::endCollectEvents()
480 osl::MutexGuard aGuard( GetLinguMutex() );
481 return mxDicEvtLstnrHelper->EndCollectEvents();
484 sal_Int16 SAL_CALL DicList::flushEvents()
486 osl::MutexGuard aGuard( GetLinguMutex() );
487 return mxDicEvtLstnrHelper->FlushEvents();
490 uno::Reference< XDictionary > SAL_CALL
491 DicList::createDictionary( const OUString& rName, const Locale& rLocale,
492 DictionaryType eDicType, const OUString& rURL )
494 osl::MutexGuard aGuard( GetLinguMutex() );
496 LanguageType nLanguage = LinguLocaleToLanguage( rLocale );
497 bool bIsWriteablePath = rURL.match( GetDictionaryWriteablePath() );
498 return new DictionaryNeo( rName, nLanguage, eDicType, rURL, bIsWriteablePath );
502 uno::Reference< XDictionaryEntry > SAL_CALL
503 DicList::queryDictionaryEntry( const OUString& rWord, const Locale& rLocale,
504 sal_Bool bSearchPosDics, sal_Bool bSearchSpellEntry )
506 osl::MutexGuard aGuard( GetLinguMutex() );
507 return SearchDicList( this, rWord, LinguLocaleToLanguage( rLocale ),
508 bSearchPosDics, bSearchSpellEntry );
512 void SAL_CALL
513 DicList::dispose()
515 osl::MutexGuard aGuard( GetLinguMutex() );
517 if (bDisposing)
518 return;
520 bDisposing = true;
521 EventObject aEvtObj( static_cast<XDictionaryList *>(this) );
523 aEvtListeners.disposeAndClear( aEvtObj );
524 if (mxDicEvtLstnrHelper.is())
525 mxDicEvtLstnrHelper->DisposeAndClear( aEvtObj );
527 //! avoid creation of dictionaries if not already done
528 if ( !aDicList.empty() )
530 DictionaryVec_t& rDicList = GetOrCreateDicList();
531 size_t nCount = rDicList.size();
532 for (size_t i = 0; i < nCount; i++)
534 // save (modified) dictionaries
535 uno::Reference< frame::XStorable > xStor( rDicList[i] , UNO_QUERY );
536 if (xStor.is())
540 if (!xStor->isReadonly() && xStor->hasLocation())
541 xStor->store();
543 catch(Exception &)
548 // release references to (members of) this object hold by
549 // dictionaries
550 if (rDicList[i].is())
551 rDicList[i]->removeDictionaryEventListener( mxDicEvtLstnrHelper );
554 mxDicEvtLstnrHelper.clear();
557 void SAL_CALL
558 DicList::addEventListener( const uno::Reference< XEventListener >& rxListener )
560 osl::MutexGuard aGuard( GetLinguMutex() );
562 if (!bDisposing && rxListener.is())
563 aEvtListeners.addInterface( rxListener );
566 void SAL_CALL
567 DicList::removeEventListener( const uno::Reference< XEventListener >& rxListener )
569 osl::MutexGuard aGuard( GetLinguMutex() );
571 if (!bDisposing && rxListener.is())
572 aEvtListeners.removeInterface( rxListener );
575 void DicList::CreateDicList()
577 bInCreation = true;
579 // look for dictionaries
580 const OUString aWriteablePath( GetDictionaryWriteablePath() );
581 std::vector< OUString > aPaths( GetDictionaryPaths() );
582 for (const OUString & aPath : aPaths)
584 const bool bIsWriteablePath = (aPath == aWriteablePath);
585 SearchForDictionaries( aDicList, aPath, bIsWriteablePath );
588 // create IgnoreAllList dictionary with empty URL (non persistent)
589 // and add it to list
590 const LanguageTag tag = comphelper::LibreOfficeKit::isActive()
591 ? LanguageTag(u"en-US"_ustr)
592 : SvtSysLocale().GetUILanguageTag();
593 std::locale loc(Translate::Create("svt", tag));
594 uno::Reference< XDictionary > xIgnAll(
595 createDictionary( Translate::get(STR_DESCRIPTION_IGNOREALLLIST, loc), LinguLanguageToLocale( LANGUAGE_NONE ),
596 DictionaryType_POSITIVE, OUString() ) );
597 if (xIgnAll.is())
599 AddUserData( xIgnAll );
600 xIgnAll->setActive( true );
601 addDictionary( xIgnAll );
605 // evaluate list of dictionaries to be activated from configuration
606 //! to suppress overwriting the list of active dictionaries in the
607 //! configuration with incorrect arguments during the following
608 //! activation of the dictionaries
609 mxDicEvtLstnrHelper->BeginCollectEvents();
610 const uno::Sequence< OUString > aActiveDics( aOpt.GetActiveDics() );
611 for (const OUString& rActiveDic : aActiveDics)
613 if (!rActiveDic.isEmpty())
615 uno::Reference< XDictionary > xDic( getDictionaryByName( rActiveDic ) );
616 if (xDic.is())
617 xDic->setActive( true );
621 // suppress collected events during creation of the dictionary list.
622 // there should be no events during creation.
623 mxDicEvtLstnrHelper->ClearEvents();
625 mxDicEvtLstnrHelper->EndCollectEvents();
627 bInCreation = false;
631 void DicList::SaveDics()
633 // save dics only if they have already been used/created.
634 //! don't create them just for the purpose of saving them !
635 if ( aDicList.empty() )
636 return;
638 // save (modified) dictionaries
639 DictionaryVec_t& rDicList = GetOrCreateDicList();
640 size_t nCount = rDicList.size();
641 for (size_t i = 0; i < nCount; i++)
643 // save (modified) dictionaries
644 uno::Reference< frame::XStorable > xStor( rDicList[i], UNO_QUERY );
645 if (xStor.is())
649 if (!xStor->isReadonly() && xStor->hasLocation())
650 xStor->store();
652 catch(Exception &)
660 // Service specific part
662 OUString SAL_CALL DicList::getImplementationName( )
664 return u"com.sun.star.lingu2.DicList"_ustr;
668 sal_Bool SAL_CALL DicList::supportsService( const OUString& ServiceName )
670 return cppu::supportsService(this, ServiceName);
673 uno::Sequence< OUString > SAL_CALL DicList::getSupportedServiceNames( )
675 return { u"com.sun.star.linguistic2.DictionaryList"_ustr };
680 static sal_Int32 lcl_GetToken( OUString &rToken,
681 const OUString &rText, sal_Int32 nPos, std::u16string_view rDelim )
683 sal_Int32 nRes = -1;
685 if (rText.isEmpty() || nPos >= rText.getLength())
686 rToken.clear();
687 else if (rDelim.empty())
689 rToken = rText;
690 if (!rToken.isEmpty())
691 nRes = rText.getLength();
693 else
695 sal_Int32 i;
696 for (i = nPos; i < rText.getLength(); ++i)
698 if (std::string_view::npos != rDelim.find( rText[i] ))
699 break;
702 if (i >= rText.getLength()) // delimiter not found
703 rToken = rText.copy( nPos );
704 else
705 rToken = rText.copy( nPos, i - nPos );
706 nRes = i + 1; // continue after found delimiter
709 return nRes;
713 static void AddInternal(
714 const uno::Reference<XDictionary> &rDic,
715 const OUString& rNew )
717 if (!rDic.is())
718 return;
720 //! TL TODO: word iterator should be used to break up the text
721 OUString aDelim(u"!\"#$%&'()*+,-/:;<=>?[]\\_^`{|}~\t \n"_ustr);
722 OSL_ENSURE(aDelim.indexOf(u'.') == -1,
723 "ensure no '.'");
725 OUString aToken;
726 sal_Int32 nPos = 0;
727 while (-1 != (nPos = lcl_GetToken( aToken, rNew, nPos, aDelim )))
729 if( !aToken.isEmpty() && !IsNumeric( aToken ) )
731 rDic->add( aToken, false, OUString() );
736 static void AddUserData( const uno::Reference< XDictionary > &rDic )
738 if (rDic.is())
740 SvtUserOptions aUserOpt;
741 AddInternal( rDic, aUserOpt.GetFullName() );
742 AddInternal( rDic, aUserOpt.GetCompany() );
743 AddInternal( rDic, aUserOpt.GetStreet() );
744 AddInternal( rDic, aUserOpt.GetCity() );
745 AddInternal( rDic, aUserOpt.GetTitle() );
746 AddInternal( rDic, aUserOpt.GetPosition() );
747 AddInternal( rDic, aUserOpt.GetEmail() );
751 static bool IsVers2OrNewer( const OUString& rFileURL, LanguageType& nLng, bool& bNeg, OUString& aDicName )
753 if (rFileURL.isEmpty())
754 return false;
755 OUString aExt;
756 sal_Int32 nPos = rFileURL.lastIndexOf( '.' );
757 if (-1 != nPos)
758 aExt = rFileURL.copy( nPos + 1 ).toAsciiLowerCase();
760 if (aExt != "dic")
761 return false;
763 // get stream to be used
764 const uno::Reference< uno::XComponentContext >& xContext( comphelper::getProcessComponentContext() );
766 // get XInputStream stream
767 uno::Reference< io::XInputStream > xStream;
770 uno::Reference< ucb::XSimpleFileAccess3 > xAccess( ucb::SimpleFileAccess::create(xContext) );
771 xStream = xAccess->openFileRead( rFileURL );
773 catch (const uno::Exception &)
775 SAL_WARN( "linguistic", "failed to get input stream" );
777 DBG_ASSERT( xStream.is(), "failed to get stream for read" );
778 if (!xStream.is())
779 return false;
781 std::unique_ptr<SvStream> pStream( utl::UcbStreamHelper::CreateStream( xStream ) );
783 int nDicVersion = ReadDicVersion(*pStream, nLng, bNeg, aDicName);
784 return 2 == nDicVersion || nDicVersion >= 5;
787 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
788 linguistic_DicList_get_implementation(
789 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
791 return cppu::acquire(new DicList());
794 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */