Bug Summary

File:home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx
Warning:line 255, column 5
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name dlistimp.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D LNG_DLLIMPLEMENTATION -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/linguistic/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
21#include <cppuhelper/factory.hxx>
22#include <i18nlangtag/mslangid.hxx>
23#include <osl/file.hxx>
24#include <tools/debug.hxx>
25#include <tools/stream.hxx>
26#include <tools/urlobj.hxx>
27#include <unotools/useroptions.hxx>
28#include <cppuhelper/supportsservice.hxx>
29#include <cppuhelper/weak.hxx>
30#include <unotools/localfilehelper.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/lang/XSingleServiceFactory.hpp>
36#include <com/sun/star/uno/Reference.h>
37#include <com/sun/star/linguistic2/DictionaryEventFlags.hpp>
38#include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
39#include <com/sun/star/ucb/SimpleFileAccess.hpp>
40#include <svtools/strings.hrc>
41#include <unotools/resmgr.hxx>
42#include <sal/log.hxx>
43
44#include "defs.hxx"
45#include "dlistimp.hxx"
46#include "dicimp.hxx"
47#include "lngopt.hxx"
48
49using namespace osl;
50using namespace com::sun::star;
51using namespace com::sun::star::lang;
52using namespace com::sun::star::uno;
53using namespace com::sun::star::linguistic2;
54using namespace linguistic;
55
56
57static bool IsVers2OrNewer( const OUString& rFileURL, LanguageType& nLng, bool& bNeg, OUString& aDicName );
58
59static void AddInternal( const uno::Reference< XDictionary > &rDic,
60 const OUString& rNew );
61static void AddUserData( const uno::Reference< XDictionary > &rDic );
62
63
64class DicEvtListenerHelper :
65 public cppu::WeakImplHelper
66 <
67 XDictionaryEventListener
68 >
69{
70 comphelper::OInterfaceContainerHelper2 aDicListEvtListeners;
71 uno::Reference< XDictionaryList > xMyDicList;
72
73 sal_Int16 nCondensedEvt;
74 sal_Int16 nNumCollectEvtListeners;
75
76public:
77 explicit DicEvtListenerHelper( const uno::Reference< XDictionaryList > &rxDicList );
78 virtual ~DicEvtListenerHelper() override;
79
80 // XEventListener
81 virtual void SAL_CALL
82 disposing( const EventObject& rSource ) override;
83
84 // XDictionaryEventListener
85 virtual void SAL_CALL
86 processDictionaryEvent( const DictionaryEvent& rDicEvent ) override;
87
88 // non-UNO functions
89 void DisposeAndClear( const EventObject &rEvtObj );
90
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; }
99};
100
101
102DicEvtListenerHelper::DicEvtListenerHelper(
103 const uno::Reference< XDictionaryList > &rxDicList ) :
104 aDicListEvtListeners ( GetLinguMutex() ),
105 xMyDicList ( rxDicList ),
106 nCondensedEvt(0), nNumCollectEvtListeners(0)
107{
108}
109
110
111DicEvtListenerHelper::~DicEvtListenerHelper()
112{
113 DBG_ASSERT(aDicListEvtListeners.getLength() == 0,do { if (true && (!(aDicListEvtListeners.getLength() ==
0))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "114" ": "), "%s", "lng : event listeners are still existing"
); } } while (false)
114 "lng : event listeners are still existing")do { if (true && (!(aDicListEvtListeners.getLength() ==
0))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "114" ": "), "%s", "lng : event listeners are still existing"
); } } while (false)
;
115}
116
117
118void DicEvtListenerHelper::DisposeAndClear( const EventObject &rEvtObj )
119{
120 aDicListEvtListeners.disposeAndClear( rEvtObj );
121}
122
123
124void SAL_CALL DicEvtListenerHelper::disposing( const EventObject& rSource )
125{
126 osl::MutexGuard aGuard( GetLinguMutex() );
127
128 uno::Reference< XInterface > xSrc( rSource.Source );
129
130 // remove event object from EventListener list
131 if (xSrc.is())
132 aDicListEvtListeners.removeInterface( xSrc );
133
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( xSrc, UNO_QUERY );
138 if (xDic.is())
139 {
140 xMyDicList->removeDictionary( xDic );
141 }
142}
143
144
145void SAL_CALL DicEvtListenerHelper::processDictionaryEvent(
146 const DictionaryEvent& rDicEvent )
147{
148 osl::MutexGuard aGuard( GetLinguMutex() );
149
150 uno::Reference< XDictionary > xDic( rDicEvent.Source, UNO_QUERY );
151 DBG_ASSERT(xDic.is(), "lng : missing event source")do { if (true && (!(xDic.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "151" ": "), "%s", "lng : missing event source"); } } while
(false)
;
152
153 // assert that there is a corresponding dictionary entry if one was
154 // added or deleted
155 DBG_ASSERT( !(rDicEvent.nEvent &do { if (true && (!(!(rDicEvent.nEvent & (DictionaryEventFlags
::ADD_ENTRY | DictionaryEventFlags::DEL_ENTRY)) || rDicEvent.
xDictionaryEntry.is()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "158" ": "), "%s", "lng : missing dictionary entry"); } }
while (false)
156 (DictionaryEventFlags::ADD_ENTRY | DictionaryEventFlags::DEL_ENTRY))do { if (true && (!(!(rDicEvent.nEvent & (DictionaryEventFlags
::ADD_ENTRY | DictionaryEventFlags::DEL_ENTRY)) || rDicEvent.
xDictionaryEntry.is()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "158" ": "), "%s", "lng : missing dictionary entry"); } }
while (false)
157 || rDicEvent.xDictionaryEntry.is(),do { if (true && (!(!(rDicEvent.nEvent & (DictionaryEventFlags
::ADD_ENTRY | DictionaryEventFlags::DEL_ENTRY)) || rDicEvent.
xDictionaryEntry.is()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "158" ": "), "%s", "lng : missing dictionary entry"); } }
while (false)
158 "lng : missing dictionary entry" )do { if (true && (!(!(rDicEvent.nEvent & (DictionaryEventFlags
::ADD_ENTRY | DictionaryEventFlags::DEL_ENTRY)) || rDicEvent.
xDictionaryEntry.is()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "158" ": "), "%s", "lng : missing dictionary entry"); } }
while (false)
;
159
160 // evaluate DictionaryEvents and update data for next DictionaryListEvent
161 DictionaryType eDicType = xDic->getDictionaryType();
162 DBG_ASSERT(eDicType != DictionaryType_MIXED,do { if (true && (!(eDicType != DictionaryType_MIXED)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "163" ": "), "%s", "lng : unexpected dictionary type"); }
} while (false)
163 "lng : unexpected dictionary type")do { if (true && (!(eDicType != DictionaryType_MIXED)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "163" ": "), "%s", "lng : unexpected dictionary type"); }
} while (false)
;
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;
190
191 if (nNumCollectEvtListeners == 0 && nCondensedEvt != 0)
192 FlushEvents();
193}
194
195
196bool DicEvtListenerHelper::AddDicListEvtListener(
197 const uno::Reference< XDictionaryListEventListener >& xListener )
198{
199 DBG_ASSERT( xListener.is(), "empty reference" )do { if (true && (!(xListener.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "199" ": "), "%s", "empty reference"); } } while (false)
;
200 sal_Int32 nCount = aDicListEvtListeners.getLength();
201 return aDicListEvtListeners.addInterface( xListener ) != nCount;
202}
203
204
205bool DicEvtListenerHelper::RemoveDicListEvtListener(
206 const uno::Reference< XDictionaryListEventListener >& xListener )
207{
208 DBG_ASSERT( xListener.is(), "empty reference" )do { if (true && (!(xListener.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "208" ": "), "%s", "empty reference"); } } while (false)
;
209 sal_Int32 nCount = aDicListEvtListeners.getLength();
210 return aDicListEvtListeners.removeInterface( xListener ) != nCount;
211}
212
213
214sal_Int16 DicEvtListenerHelper::EndCollectEvents()
215{
216 DBG_ASSERT(nNumCollectEvtListeners > 0, "lng: mismatched function call")do { if (true && (!(nNumCollectEvtListeners > 0)))
{ sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "216" ": "), "%s", "lng: mismatched function call"); } }
while (false)
;
217 if (nNumCollectEvtListeners > 0)
218 {
219 FlushEvents();
220 nNumCollectEvtListeners--;
221 }
222
223 return nNumCollectEvtListeners;
224}
225
226
227sal_Int16 DicEvtListenerHelper::FlushEvents()
228{
229 if (0 != nCondensedEvt)
230 {
231 // build DictionaryListEvent to pass on to listeners
232 uno::Sequence< DictionaryEvent > aDicEvents;
233 DictionaryListEvent aEvent( xMyDicList, nCondensedEvt, aDicEvents );
234
235 // pass on event
236 aDicListEvtListeners.notifyEach( &XDictionaryListEventListener::processDictionaryListEvent, aEvent );
237
238 // clear "list" of events
239 nCondensedEvt = 0;
240 }
241
242 return nNumCollectEvtListeners;
243}
244
245
246void DicList::MyAppExitListener::AtExit()
247{
248 rMyDicList.SaveDics();
249}
250
251
252DicList::DicList() :
253 aEvtListeners ( GetLinguMutex() )
254{
255 mxDicEvtLstnrHelper = new DicEvtListenerHelper( this );
2
Called C++ object pointer is null
256 bDisposing = false;
257 bInCreation = false;
258
259 mxExitListener = new MyAppExitListener( *this );
260 mxExitListener->Activate();
261}
262
263DicList::~DicList()
264{
265 mxExitListener->Deactivate();
266}
267
268
269void DicList::SearchForDictionaries(
270 DictionaryVec_t&rDicList,
271 const OUString &rDicDirURL,
272 bool bIsWriteablePath )
273{
274 osl::MutexGuard aGuard( GetLinguMutex() );
275
276 const uno::Sequence< OUString > aDirCnt( utl::LocalFileHelper::
277 GetFolderContents( rDicDirURL, false ) );
278
279 for (const OUString& aURL : aDirCnt)
280 {
281 LanguageType nLang = LANGUAGE_NONELanguageType(0x00FF);
282 bool bNeg = false;
283 OUString aDicTitle = "";
284
285 if(!::IsVers2OrNewer( aURL, nLang, bNeg, aDicTitle ))
286 {
287 // When not
288 sal_Int32 nPos = aURL.indexOf('.');
289 OUString aExt( aURL.copy(nPos + 1).toAsciiLowerCase() );
290
291 if ("dcn" == aExt) // negative
292 bNeg = true;
293 else if ("dcp" == aExt) // positive
294 bNeg = false;
295 else
296 continue; // other files
297 }
298
299 // Record in the list of Dictionaries
300 // When it already exists don't record
301 LanguageType nSystemLanguage = MsLangId::getSystemLanguage();
302 OUString aTmp1 = ToLower( aURL, nSystemLanguage );
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++)
310 {
311 aTmp2 = rDicList[j]->getName();
312 aTmp2 = ToLower( aTmp2, nSystemLanguage );
313 if(aTmp1 == aTmp2)
314 break;
315 }
316 if(j >= nCount) // dictionary not yet in DicList
317 {
318 // get decoded dictionary file name
319 INetURLObject aURLObj( aURL );
320 OUString aDicName = aURLObj.getName( INetURLObject::LAST_SEGMENT,
321 true, INetURLObject::DecodeMechanism::WithCharset );
322
323 DictionaryType eType = bNeg ? DictionaryType_NEGATIVE : DictionaryType_POSITIVE;
324 uno::Reference< XDictionary > xDic =
325 new DictionaryNeo( aDicTitle.isEmpty() ? aDicName : aDicTitle, nLang, eType, aURL, bIsWriteablePath );
326
327 addDictionary( xDic );
328 nCount++;
329 }
330 }
331}
332
333
334sal_Int32 DicList::GetDicPos(const uno::Reference< XDictionary > &xDic)
335{
336 osl::MutexGuard aGuard( GetLinguMutex() );
337
338 DictionaryVec_t& rDicList = GetOrCreateDicList();
339 size_t n = rDicList.size();
340 for (size_t i = 0; i < n; i++)
341 {
342 if ( rDicList[i] == xDic )
343 return i;
344 }
345 return -1;
346}
347
348sal_Int16 SAL_CALL DicList::getCount()
349{
350 osl::MutexGuard aGuard( GetLinguMutex() );
351 return static_cast< sal_Int16 >(GetOrCreateDicList().size());
352}
353
354uno::Sequence< uno::Reference< XDictionary > > SAL_CALL
355 DicList::getDictionaries()
356{
357 osl::MutexGuard aGuard( GetLinguMutex() );
358
359 DictionaryVec_t& rDicList = GetOrCreateDicList();
360
361 return comphelper::containerToSequence(rDicList);
362}
363
364uno::Reference< XDictionary > SAL_CALL
365 DicList::getDictionaryByName( const OUString& aDictionaryName )
366{
367 osl::MutexGuard aGuard( GetLinguMutex() );
368
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++)
373 {
374 const uno::Reference< XDictionary > &rDic = rDicList[i];
375 if (rDic.is() && rDic->getName() == aDictionaryName)
376 {
377 xDic = rDic;
378 break;
379 }
380 }
381
382 return xDic;
383}
384
385sal_Bool SAL_CALL DicList::addDictionary(
386 const uno::Reference< XDictionary >& xDictionary )
387{
388 osl::MutexGuard aGuard( GetLinguMutex() );
389
390 if (bDisposing)
391 return false;
392
393 bool bRes = false;
394 if (xDictionary.is())
395 {
396 DictionaryVec_t& rDicList = GetOrCreateDicList();
397 rDicList.push_back( xDictionary );
398 bRes = true;
399
400 // add listener helper to the dictionaries listener lists
401 xDictionary->addDictionaryEventListener( mxDicEvtLstnrHelper.get() );
402 }
403 return bRes;
404}
405
406sal_Bool SAL_CALL
407 DicList::removeDictionary( const uno::Reference< XDictionary >& xDictionary )
408{
409 osl::MutexGuard aGuard( GetLinguMutex() );
410
411 if (bDisposing)
412 return false;
413
414 bool bRes = false;
415 sal_Int32 nPos = GetDicPos( xDictionary );
416 if (nPos >= 0)
417 {
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")do { if (true && (!(xDic.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "421" ": "), "%s", "lng : empty reference"); } } while (
false)
;
422 if (xDic.is())
423 {
424 // deactivate dictionary if not already done
425 xDic->setActive( false );
426
427 xDic->removeDictionaryEventListener( mxDicEvtLstnrHelper.get() );
428 }
429
430 // remove element at nPos
431 rDicList.erase( rDicList.begin() + nPos );
432 bRes = true;
433 }
434 return bRes;
435}
436
437sal_Bool SAL_CALL DicList::addDictionaryListEventListener(
438 const uno::Reference< XDictionaryListEventListener >& xListener,
439 sal_Bool bReceiveVerbose )
440{
441 osl::MutexGuard aGuard( GetLinguMutex() );
442
443 if (bDisposing)
444 return false;
445
446 DBG_ASSERT(!bReceiveVerbose, "lng : not yet supported")do { if (true && (!(!bReceiveVerbose))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "446" ": "), "%s", "lng : not yet supported"); } } while
(false)
;
447
448 bool bRes = false;
449 if (xListener.is()) //! don't add empty references
450 {
451 bRes = mxDicEvtLstnrHelper->AddDicListEvtListener( xListener );
452 }
453 return bRes;
454}
455
456sal_Bool SAL_CALL DicList::removeDictionaryListEventListener(
457 const uno::Reference< XDictionaryListEventListener >& xListener )
458{
459 osl::MutexGuard aGuard( GetLinguMutex() );
460
461 if (bDisposing)
462 return false;
463
464 bool bRes = false;
465 if(xListener.is())
466 {
467 bRes = mxDicEvtLstnrHelper->RemoveDicListEvtListener( xListener );
468 }
469 return bRes;
470}
471
472sal_Int16 SAL_CALL DicList::beginCollectEvents()
473{
474 osl::MutexGuard aGuard( GetLinguMutex() );
475 return mxDicEvtLstnrHelper->BeginCollectEvents();
476}
477
478sal_Int16 SAL_CALL DicList::endCollectEvents()
479{
480 osl::MutexGuard aGuard( GetLinguMutex() );
481 return mxDicEvtLstnrHelper->EndCollectEvents();
482}
483
484sal_Int16 SAL_CALL DicList::flushEvents()
485{
486 osl::MutexGuard aGuard( GetLinguMutex() );
487 return mxDicEvtLstnrHelper->FlushEvents();
488}
489
490uno::Reference< XDictionary > SAL_CALL
491 DicList::createDictionary( const OUString& rName, const Locale& rLocale,
492 DictionaryType eDicType, const OUString& rURL )
493{
494 osl::MutexGuard aGuard( GetLinguMutex() );
495
496 LanguageType nLanguage = LinguLocaleToLanguage( rLocale );
497 bool bIsWriteablePath = rURL.match( GetDictionaryWriteablePath() );
498 return new DictionaryNeo( rName, nLanguage, eDicType, rURL, bIsWriteablePath );
499}
500
501
502uno::Reference< XDictionaryEntry > SAL_CALL
503 DicList::queryDictionaryEntry( const OUString& rWord, const Locale& rLocale,
504 sal_Bool bSearchPosDics, sal_Bool bSearchSpellEntry )
505{
506 osl::MutexGuard aGuard( GetLinguMutex() );
507 return SearchDicList( this, rWord, LinguLocaleToLanguage( rLocale ),
508 bSearchPosDics, bSearchSpellEntry );
509}
510
511
512void SAL_CALL
513 DicList::dispose()
514{
515 osl::MutexGuard aGuard( GetLinguMutex() );
516
517 if (bDisposing)
518 return;
519
520 bDisposing = true;
521 EventObject aEvtObj( static_cast<XDictionaryList *>(this) );
522
523 aEvtListeners.disposeAndClear( aEvtObj );
524 if (mxDicEvtLstnrHelper.is())
525 mxDicEvtLstnrHelper->DisposeAndClear( aEvtObj );
526
527 //! avoid creation of dictionaries if not already done
528 if ( !aDicList.empty() )
529 {
530 DictionaryVec_t& rDicList = GetOrCreateDicList();
531 size_t nCount = rDicList.size();
532 for (size_t i = 0; i < nCount; i++)
533 {
534 // save (modified) dictionaries
535 uno::Reference< frame::XStorable > xStor( rDicList[i] , UNO_QUERY );
536 if (xStor.is())
537 {
538 try
539 {
540 if (!xStor->isReadonly() && xStor->hasLocation())
541 xStor->store();
542 }
543 catch(Exception &)
544 {
545 }
546 }
547
548 // release references to (members of) this object hold by
549 // dictionaries
550 if (rDicList[i].is())
551 rDicList[i]->removeDictionaryEventListener( mxDicEvtLstnrHelper.get() );
552 }
553 }
554 mxDicEvtLstnrHelper.clear();
555}
556
557void SAL_CALL
558 DicList::addEventListener( const uno::Reference< XEventListener >& rxListener )
559{
560 osl::MutexGuard aGuard( GetLinguMutex() );
561
562 if (!bDisposing && rxListener.is())
563 aEvtListeners.addInterface( rxListener );
564}
565
566void SAL_CALL
567 DicList::removeEventListener( const uno::Reference< XEventListener >& rxListener )
568{
569 osl::MutexGuard aGuard( GetLinguMutex() );
570
571 if (!bDisposing && rxListener.is())
572 aEvtListeners.removeInterface( rxListener );
573}
574
575void DicList::CreateDicList()
576{
577 bInCreation = true;
578
579 // look for dictionaries
580 const OUString aWriteablePath( GetDictionaryWriteablePath() );
581 std::vector< OUString > aPaths( GetDictionaryPaths() );
582 for (const OUString & aPath : aPaths)
583 {
584 const bool bIsWriteablePath = (aPath == aWriteablePath);
585 SearchForDictionaries( aDicList, aPath, bIsWriteablePath );
586 }
587
588 // create IgnoreAllList dictionary with empty URL (non persistent)
589 // and add it to list
590 std::locale loc(Translate::Create("svt"));
591 uno::Reference< XDictionary > xIgnAll(
592 createDictionary( Translate::get(STR_DESCRIPTION_IGNOREALLLISTreinterpret_cast<char const *>("STR_DESCRIPTION_IGNOREALLLIST"
"\004" u8"List of Ignored Words")
, loc), LinguLanguageToLocale( LANGUAGE_NONELanguageType(0x00FF) ),
593 DictionaryType_POSITIVE, OUString() ) );
594 if (xIgnAll.is())
595 {
596 AddUserData( xIgnAll );
597 xIgnAll->setActive( true );
598 addDictionary( xIgnAll );
599 }
600
601
602 // evaluate list of dictionaries to be activated from configuration
603 //! to suppress overwriting the list of active dictionaries in the
604 //! configuration with incorrect arguments during the following
605 //! activation of the dictionaries
606 mxDicEvtLstnrHelper->BeginCollectEvents();
607 const uno::Sequence< OUString > aActiveDics( aOpt.GetActiveDics() );
608 for (const OUString& rActiveDic : aActiveDics)
609 {
610 if (!rActiveDic.isEmpty())
611 {
612 uno::Reference< XDictionary > xDic( getDictionaryByName( rActiveDic ) );
613 if (xDic.is())
614 xDic->setActive( true );
615 }
616 }
617
618 // suppress collected events during creation of the dictionary list.
619 // there should be no events during creation.
620 mxDicEvtLstnrHelper->ClearEvents();
621
622 mxDicEvtLstnrHelper->EndCollectEvents();
623
624 bInCreation = false;
625}
626
627
628void DicList::SaveDics()
629{
630 // save dics only if they have already been used/created.
631 //! don't create them just for the purpose of saving them !
632 if ( aDicList.empty() )
633 return;
634
635 // save (modified) dictionaries
636 DictionaryVec_t& rDicList = GetOrCreateDicList();
637 size_t nCount = rDicList.size();
638 for (size_t i = 0; i < nCount; i++)
639 {
640 // save (modified) dictionaries
641 uno::Reference< frame::XStorable > xStor( rDicList[i], UNO_QUERY );
642 if (xStor.is())
643 {
644 try
645 {
646 if (!xStor->isReadonly() && xStor->hasLocation())
647 xStor->store();
648 }
649 catch(Exception &)
650 {
651 }
652 }
653 }
654}
655
656
657// Service specific part
658
659OUString SAL_CALL DicList::getImplementationName( )
660{
661 return "com.sun.star.lingu2.DicList";
662}
663
664
665sal_Bool SAL_CALL DicList::supportsService( const OUString& ServiceName )
666{
667 return cppu::supportsService(this, ServiceName);
668}
669
670uno::Sequence< OUString > SAL_CALL DicList::getSupportedServiceNames( )
671{
672 return { "com.sun.star.linguistic2.DictionaryList" };
673}
674
675
676
677static sal_Int32 lcl_GetToken( OUString &rToken,
678 const OUString &rText, sal_Int32 nPos, const OUString &rDelim )
679{
680 sal_Int32 nRes = -1;
681
682 if (rText.isEmpty() || nPos >= rText.getLength())
683 rToken.clear();
684 else if (rDelim.isEmpty())
685 {
686 rToken = rText;
687 if (!rToken.isEmpty())
688 nRes = rText.getLength();
689 }
690 else
691 {
692 sal_Int32 i;
693 for (i = nPos; i < rText.getLength(); ++i)
694 {
695 if (-1 != rDelim.indexOf( rText[i] ))
696 break;
697 }
698
699 if (i >= rText.getLength()) // delimiter not found
700 rToken = rText.copy( nPos );
701 else
702 rToken = rText.copy( nPos, i - nPos );
703 nRes = i + 1; // continue after found delimiter
704 }
705
706 return nRes;
707}
708
709
710static void AddInternal(
711 const uno::Reference<XDictionary> &rDic,
712 const OUString& rNew )
713{
714 if (!rDic.is())
715 return;
716
717 //! TL TODO: word iterator should be used to break up the text
718 OUString aDelim("!\"#$%&'()*+,-/:;<=>?[]\\_^`{|}~\t \n");
719 OSL_ENSURE(aDelim.indexOf(u'.') == -1,do { if (true && (!(aDelim.indexOf(u'.') == -1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "720" ": "), "%s", "ensure no '.'"); } } while (false)
720 "ensure no '.'")do { if (true && (!(aDelim.indexOf(u'.') == -1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "720" ": "), "%s", "ensure no '.'"); } } while (false)
;
721
722 OUString aToken;
723 sal_Int32 nPos = 0;
724 while (-1 != (nPos = lcl_GetToken( aToken, rNew, nPos, aDelim )))
725 {
726 if( !aToken.isEmpty() && !IsNumeric( aToken ) )
727 {
728 rDic->add( aToken, false, OUString() );
729 }
730 }
731}
732
733static void AddUserData( const uno::Reference< XDictionary > &rDic )
734{
735 if (rDic.is())
736 {
737 SvtUserOptions aUserOpt;
738 AddInternal( rDic, aUserOpt.GetFullName() );
739 AddInternal( rDic, aUserOpt.GetCompany() );
740 AddInternal( rDic, aUserOpt.GetStreet() );
741 AddInternal( rDic, aUserOpt.GetCity() );
742 AddInternal( rDic, aUserOpt.GetTitle() );
743 AddInternal( rDic, aUserOpt.GetPosition() );
744 AddInternal( rDic, aUserOpt.GetEmail() );
745 }
746}
747
748static bool IsVers2OrNewer( const OUString& rFileURL, LanguageType& nLng, bool& bNeg, OUString& aDicName )
749{
750 if (rFileURL.isEmpty())
751 return false;
752 OUString aExt;
753 sal_Int32 nPos = rFileURL.lastIndexOf( '.' );
754 if (-1 != nPos)
755 aExt = rFileURL.copy( nPos + 1 ).toAsciiLowerCase();
756
757 if (aExt != "dic")
758 return false;
759
760 // get stream to be used
761 uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
762
763 // get XInputStream stream
764 uno::Reference< io::XInputStream > xStream;
765 try
766 {
767 uno::Reference< ucb::XSimpleFileAccess3 > xAccess( ucb::SimpleFileAccess::create(xContext) );
768 xStream = xAccess->openFileRead( rFileURL );
769 }
770 catch (const uno::Exception &)
771 {
772 SAL_WARN( "linguistic", "failed to get input stream" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "linguistic")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "failed to get input stream"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("linguistic"
), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "772" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "failed to get input stream"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"failed to get input stream"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("linguistic"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "772" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "failed to get input stream") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("linguistic"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "772" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "failed to get input stream"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"failed to get input stream"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("linguistic"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "772" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
773 }
774 DBG_ASSERT( xStream.is(), "failed to get stream for read" )do { if (true && (!(xStream.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/linguistic/source/dlistimp.cxx"
":" "774" ": "), "%s", "failed to get stream for read"); } }
while (false)
;
775 if (!xStream.is())
776 return false;
777
778 std::unique_ptr<SvStream> pStream( utl::UcbStreamHelper::CreateStream( xStream ) );
779
780 int nDicVersion = ReadDicVersion(*pStream, nLng, bNeg, aDicName);
781 return 2 == nDicVersion || nDicVersion >= 5;
782}
783
784extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) css::uno::XInterface*
785linguistic_DicList_get_implementation(
786 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
787{
788 return cppu::acquire(static_cast<cppu::OWeakObject*>(new DicList()));
1
Calling default constructor for 'DicList'
789}
790
791/* vim:set shiftwidth=4 softtabstop=4 expandtab: */