office-gobmx/linguistic/source/dicimp.cxx
Stephan Bergmann e57ca02849 Remove dynamic exception specifications
...(for now, from LIBO_INTERNAL_CODE only).  See the mail thread starting at
<https://lists.freedesktop.org/archives/libreoffice/2017-January/076665.html>
"Dynamic Exception Specifications" for details.

Most changes have been done automatically by the rewriting loplugin:dynexcspec
(after enabling the rewriting mode, to be committed shortly).  The way it only
removes exception specs from declarations if it also sees a definition, it
identified some dead declarations-w/o-definitions (that have been removed
manually) and some cases where a definition appeared in multiple include files
(which have also been cleaned up manually).  There's also been cases of macro
paramters (that were used to abstract over exception specs) that have become
unused now (and been removed).

Furthermore, some code needed to be cleaned up manually
(avmedia/source/quicktime/ and connectivity/source/drivers/kab/), as I had no
configurations available that would actually build that code.  Missing @throws
documentation has not been applied in such manual clean-up.

Change-Id: I3408691256c9b0c12bc5332de976743626e13960
Reviewed-on: https://gerrit.libreoffice.org/33574
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2017-01-26 12:54:43 +00:00

1034 lines
29 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <cppuhelper/factory.hxx>
#include <dicimp.hxx>
#include <hyphdsp.hxx>
#include <i18nlangtag/lang.h>
#include <i18nlangtag/languagetag.hxx>
#include <osl/mutex.hxx>
#include <tools/debug.hxx>
#include <tools/stream.hxx>
#include <tools/urlobj.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <comphelper/sequence.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
#include <com/sun/star/linguistic2/DictionaryType.hpp>
#include <com/sun/star/linguistic2/DictionaryEventFlags.hpp>
#include <com/sun/star/registry/XRegistryKey.hpp>
#include <com/sun/star/io/TempFile.hpp>
#include <com/sun/star/io/XInputStream.hpp>
#include <com/sun/star/io/XOutputStream.hpp>
#include "defs.hxx"
#include <algorithm>
using namespace utl;
using namespace osl;
using namespace com::sun::star;
using namespace com::sun::star::lang;
using namespace com::sun::star::uno;
using namespace com::sun::star::linguistic2;
using namespace linguistic;
#define BUFSIZE 4096
#define VERS2_NOLANGUAGE 1024
#define MAX_HEADER_LENGTH 16
static const sal_Char* const pVerStr2 = "WBSWG2";
static const sal_Char* const pVerStr5 = "WBSWG5";
static const sal_Char* const pVerStr6 = "WBSWG6";
static const sal_Char* const pVerOOo7 = "OOoUserDict1";
static const sal_Int16 DIC_VERSION_DONTKNOW = -1;
static const sal_Int16 DIC_VERSION_2 = 2;
static const sal_Int16 DIC_VERSION_5 = 5;
static const sal_Int16 DIC_VERSION_6 = 6;
static const sal_Int16 DIC_VERSION_7 = 7;
static bool getTag(const OString &rLine, const sal_Char *pTagName,
OString &rTagValue)
{
sal_Int32 nPos = rLine.indexOf(pTagName);
if (nPos == -1)
return false;
rTagValue = comphelper::string::strip(rLine.copy(nPos + rtl_str_getLength(pTagName)),
' ');
return true;
}
sal_Int16 ReadDicVersion( SvStreamPtr &rpStream, sal_uInt16 &nLng, bool &bNeg )
{
// Sniff the header
sal_Int16 nDicVersion = DIC_VERSION_DONTKNOW;
sal_Char pMagicHeader[MAX_HEADER_LENGTH];
nLng = LANGUAGE_NONE;
bNeg = false;
if (!rpStream.get() || rpStream->GetError())
return -1;
sal_uInt64 const nSniffPos = rpStream->Tell();
static std::size_t nVerOOo7Len = sal::static_int_cast< std::size_t >(strlen( pVerOOo7 ));
pMagicHeader[ nVerOOo7Len ] = '\0';
if ((rpStream->ReadBytes(static_cast<void *>(pMagicHeader), nVerOOo7Len) == nVerOOo7Len) &&
!strcmp(pMagicHeader, pVerOOo7))
{
bool bSuccess;
OString aLine;
nDicVersion = DIC_VERSION_7;
// 1st skip magic / header line
rpStream->ReadLine(aLine);
// 2nd line: language all | en-US | pt-BR ...
while ((bSuccess = rpStream->ReadLine(aLine)))
{
OString aTagValue;
if (aLine[0] == '#') // skip comments
continue;
// lang: field
if (getTag(aLine, "lang: ", aTagValue))
{
if (aTagValue == "<none>")
nLng = LANGUAGE_NONE;
else
nLng = LanguageTag::convertToLanguageType(
OStringToOUString( aTagValue, RTL_TEXTENCODING_ASCII_US));
}
// type: negative / positive
if (getTag(aLine, "type: ", aTagValue))
{
if (aTagValue == "negative")
bNeg = true;
else
bNeg = false;
}
if (aLine.indexOf("---") != -1) // end of header
break;
}
if (!bSuccess)
return -2;
}
else
{
sal_uInt16 nLen;
rpStream->Seek (nSniffPos );
rpStream->ReadUInt16( nLen );
if (nLen >= MAX_HEADER_LENGTH)
return -1;
rpStream->ReadBytes(pMagicHeader, nLen);
pMagicHeader[nLen] = '\0';
// Check version magic
if (0 == strcmp( pMagicHeader, pVerStr6 ))
nDicVersion = DIC_VERSION_6;
else if (0 == strcmp( pMagicHeader, pVerStr5 ))
nDicVersion = DIC_VERSION_5;
else if (0 == strcmp( pMagicHeader, pVerStr2 ))
nDicVersion = DIC_VERSION_2;
else
nDicVersion = DIC_VERSION_DONTKNOW;
if (DIC_VERSION_2 == nDicVersion ||
DIC_VERSION_5 == nDicVersion ||
DIC_VERSION_6 == nDicVersion)
{
// The language of the dictionary
rpStream->ReadUInt16( nLng );
if (VERS2_NOLANGUAGE == nLng)
nLng = LANGUAGE_NONE;
// Negative Flag
rpStream->ReadCharAsBool( bNeg );
}
}
return nDicVersion;
}
DictionaryNeo::DictionaryNeo(const OUString &rName,
sal_Int16 nLang, DictionaryType eType,
const OUString &rMainURL,
bool bWriteable) :
aDicEvtListeners( GetLinguMutex() ),
aDicName (rName),
aMainURL (rMainURL),
eDicType (eType),
nLanguage (nLang)
{
nDicVersion = DIC_VERSION_DONTKNOW;
bNeedEntries = true;
bIsModified = bIsActive = false;
bIsReadonly = !bWriteable;
if( !rMainURL.isEmpty())
{
bool bExists = FileExists( rMainURL );
if( !bExists )
{
// save new dictionaries with in Format 7 (UTF8 plain text)
nDicVersion = DIC_VERSION_7;
//! create physical representation of an **empty** dictionary
//! that could be found by the dictionary-list implementation
// (Note: empty dictionaries are not just empty files!)
DBG_ASSERT( !bIsReadonly,
"DictionaryNeo: dictionaries should be writeable if they are to be saved" );
if (!bIsReadonly)
saveEntries( rMainURL );
bNeedEntries = false;
}
}
else
{
// non persistent dictionaries (like IgnoreAllList) should always be writable
bIsReadonly = false;
bNeedEntries = false;
}
}
DictionaryNeo::~DictionaryNeo()
{
}
sal_uLong DictionaryNeo::loadEntries(const OUString &rMainURL)
{
MutexGuard aGuard( GetLinguMutex() );
// counter check that it is safe to set bIsModified to sal_False at
// the end of the function
DBG_ASSERT(!bIsModified, "lng : dictionary already modified!");
// function should only be called once in order to load entries from file
bNeedEntries = false;
if (rMainURL.isEmpty())
return 0;
uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
// get XInputStream stream
uno::Reference< io::XInputStream > xStream;
try
{
uno::Reference< ucb::XSimpleFileAccess3 > xAccess( ucb::SimpleFileAccess::create(xContext) );
xStream = xAccess->openFileRead( rMainURL );
}
catch (const uno::Exception &)
{
SAL_WARN( "linguistic", "failed to get input stream" );
}
if (!xStream.is())
return static_cast< sal_uLong >(-1);
SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) );
// read header
bool bNegativ;
sal_uInt16 nLang;
nDicVersion = ReadDicVersion(pStream, nLang, bNegativ);
sal_uLong nErr = pStream->GetError();
if (0 != nErr)
return nErr;
nLanguage = nLang;
eDicType = bNegativ ? DictionaryType_NEGATIVE : DictionaryType_POSITIVE;
rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
if (nDicVersion >= DIC_VERSION_6)
eEnc = RTL_TEXTENCODING_UTF8;
aEntries.clear();
if (DIC_VERSION_6 == nDicVersion ||
DIC_VERSION_5 == nDicVersion ||
DIC_VERSION_2 == nDicVersion)
{
sal_uInt16 nLen = 0;
sal_Char aWordBuf[ BUFSIZE ];
// Read the first word
if (!pStream->IsEof())
{
pStream->ReadUInt16( nLen );
if (0 != (nErr = pStream->GetError()))
return nErr;
if ( nLen < BUFSIZE )
{
pStream->ReadBytes(aWordBuf, nLen);
if (0 != (nErr = pStream->GetError()))
return nErr;
*(aWordBuf + nLen) = 0;
}
else
return SVSTREAM_READ_ERROR;
}
while(!pStream->IsEof())
{
// Read from file
// Paste in dictionary without converting
if(*aWordBuf)
{
OUString aText(aWordBuf, rtl_str_getLength(aWordBuf), eEnc);
uno::Reference< XDictionaryEntry > xEntry =
new DicEntry( aText, bNegativ );
addEntry_Impl( xEntry, true ); //! don't launch events here
}
pStream->ReadUInt16( nLen );
if (pStream->IsEof())
break;
if (0 != (nErr = pStream->GetError()))
return nErr;
if (nLen < BUFSIZE)
{
pStream->ReadBytes(aWordBuf, nLen);
if (0 != (nErr = pStream->GetError()))
return nErr;
}
else
return SVSTREAM_READ_ERROR;
*(aWordBuf + nLen) = 0;
}
}
else if (DIC_VERSION_7 == nDicVersion)
{
OString aLine;
// remaining lines - stock strings (a [==] b)
while (pStream->ReadLine(aLine))
{
if (aLine[0] == '#') // skip comments
continue;
OUString aText = OStringToOUString(aLine, RTL_TEXTENCODING_UTF8);
uno::Reference< XDictionaryEntry > xEntry =
new DicEntry( aText, eDicType == DictionaryType_NEGATIVE );
addEntry_Impl( xEntry, true ); //! don't launch events here
}
}
SAL_WARN_IF(!isSorted(), "linguistic", "dictionary is not sorted");
// since this routine should be called only initially (prior to any
// modification to be saved) we reset the bIsModified flag here that
// was implicitly set by addEntry_Impl
bIsModified = false;
return pStream->GetError();
}
static OString formatForSave(const uno::Reference< XDictionaryEntry > &xEntry,
rtl_TextEncoding eEnc )
{
OStringBuffer aStr(OUStringToOString(xEntry->getDictionaryWord(), eEnc));
if (xEntry->isNegative())
{
aStr.append("==");
aStr.append(OUStringToOString(xEntry->getReplacementText(), eEnc));
}
return aStr.makeStringAndClear();
}
sal_uLong DictionaryNeo::saveEntries(const OUString &rURL)
{
MutexGuard aGuard( GetLinguMutex() );
if (rURL.isEmpty())
return 0;
DBG_ASSERT(!INetURLObject( rURL ).HasError(), "lng : invalid URL");
uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
// get XOutputStream stream
uno::Reference<io::XStream> xStream;
try
{
xStream = io::TempFile::create(xContext);
}
catch (const uno::Exception &)
{
DBG_ASSERT( false, "failed to get input stream" );
}
if (!xStream.is())
return static_cast< sal_uLong >(-1);
SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) );
// Always write as the latest version, i.e. DIC_VERSION_7
rtl_TextEncoding eEnc = RTL_TEXTENCODING_UTF8;
pStream->WriteLine(OString(pVerOOo7));
sal_uLong nErr = pStream->GetError();
if (0 != nErr)
return nErr;
/* XXX: the <none> case could be differentiated, is it absence or
* undetermined or multiple? Earlier versions did not know about 'und' and
* 'mul' and 'zxx' codes. Sync with ReadDicVersion() */
if (LinguIsUnspecified(nLanguage))
pStream->WriteLine(OString("lang: <none>"));
else
{
OStringBuffer aLine("lang: ");
aLine.append(OUStringToOString(LanguageTag::convertToBcp47(nLanguage), eEnc));
pStream->WriteLine(aLine.makeStringAndClear());
}
if (0 != (nErr = pStream->GetError()))
return nErr;
if (eDicType == DictionaryType_POSITIVE)
pStream->WriteLine(OString("type: positive"));
else
pStream->WriteLine(OString("type: negative"));
if (0 != (nErr = pStream->GetError()))
return nErr;
pStream->WriteLine(OString("---"));
if (0 != (nErr = pStream->GetError()))
return nErr;
for (Reference<XDictionaryEntry> & aEntrie : aEntries)
{
OString aOutStr = formatForSave(aEntrie, eEnc);
pStream->WriteLine (aOutStr);
if (0 != (nErr = pStream->GetError()))
return nErr;
}
try
{
pStream.reset();
uno::Reference< ucb::XSimpleFileAccess3 > xAccess(ucb::SimpleFileAccess::create(xContext));
Reference<io::XInputStream> xInputStream(xStream, UNO_QUERY_THROW);
uno::Reference<io::XSeekable> xSeek(xInputStream, UNO_QUERY_THROW);
xSeek->seek(0);
xAccess->writeFile(rURL, xInputStream);
//If we are migrating from an older version, then on first successful
//write, we're now converted to the latest version, i.e. DIC_VERSION_7
nDicVersion = DIC_VERSION_7;
}
catch (const uno::Exception &)
{
DBG_ASSERT( false, "failed to write stream" );
return static_cast< sal_uLong >(-1);
}
return nErr;
}
void DictionaryNeo::launchEvent(sal_Int16 nEvent,
const uno::Reference< XDictionaryEntry >& xEntry)
{
MutexGuard aGuard( GetLinguMutex() );
DictionaryEvent aEvt;
aEvt.Source = uno::Reference< XDictionary >( this );
aEvt.nEvent = nEvent;
aEvt.xDictionaryEntry = xEntry;
aDicEvtListeners.notifyEach( &XDictionaryEventListener::processDictionaryEvent, aEvt);
}
int DictionaryNeo::cmpDicEntry(const OUString& rWord1,
const OUString &rWord2,
bool bSimilarOnly)
{
MutexGuard aGuard( GetLinguMutex() );
// returns 0 if rWord1 is equal to rWord2
// " a value < 0 if rWord1 is less than rWord2
// " a value > 0 if rWord1 is greater than rWord2
int nRes = 0;
sal_Int32 nLen1 = rWord1.getLength(),
nLen2 = rWord2.getLength();
if (bSimilarOnly)
{
const sal_Unicode cChar = '.';
if (nLen1 && cChar == rWord1[ nLen1 - 1 ])
nLen1--;
if (nLen2 && cChar == rWord2[ nLen2 - 1 ])
nLen2--;
}
const sal_Unicode cIgnChar = '=';
const sal_Unicode cIgnBeg = '['; // for alternative hyphenation, eg. Schif[f]fahrt, Zuc[1k]ker
const sal_Unicode cIgnEnd = ']'; // planned: gee"[1-/e]rfde or ge[-/1e]e"rfde (gee"rfde -> ge=erfde)
sal_Int32 nIdx1 = 0,
nIdx2 = 0,
nNumIgnChar1 = 0,
nNumIgnChar2 = 0;
bool IgnState;
sal_Int32 nDiff = 0;
sal_Unicode cChar1 = '\0';
sal_Unicode cChar2 = '\0';
do
{
// skip chars to be ignored
IgnState = false;
while (nIdx1 < nLen1 && ((cChar1 = rWord1[ nIdx1 ]) == cIgnChar || cChar1 == cIgnBeg || IgnState ))
{
if ( cChar1 == cIgnBeg )
IgnState = true;
else if (cChar1 == cIgnEnd)
IgnState = false;
nIdx1++;
nNumIgnChar1++;
}
IgnState = false;
while (nIdx2 < nLen2 && ((cChar2 = rWord2[ nIdx2 ]) == cIgnChar || cChar2 == cIgnBeg || IgnState ))
{
if ( cChar2 == cIgnBeg )
IgnState = true;
else if (cChar2 == cIgnEnd)
IgnState = false;
nIdx2++;
nNumIgnChar2++;
}
if (nIdx1 < nLen1 && nIdx2 < nLen2)
{
nDiff = cChar1 - cChar2;
if (nDiff)
break;
nIdx1++;
nIdx2++;
}
} while (nIdx1 < nLen1 && nIdx2 < nLen2);
if (nDiff)
nRes = nDiff;
else
{ // the string with the smallest count of not ignored chars is the
// shorter one
// count remaining IgnChars
IgnState = false;
while (nIdx1 < nLen1 )
{
if (rWord1[ nIdx1 ] == cIgnBeg)
IgnState = true;
if (IgnState || rWord1[ nIdx1 ] == cIgnChar)
nNumIgnChar1++;
if (rWord1[ nIdx1] == cIgnEnd)
IgnState = false;
nIdx1++;
}
IgnState = false;
while (nIdx2 < nLen2 )
{
if (rWord2[ nIdx2 ] == cIgnBeg)
IgnState = true;
if (IgnState || rWord2[ nIdx2 ] == cIgnChar)
nNumIgnChar2++;
if (rWord2[ nIdx2 ] == cIgnEnd)
IgnState = false;
nIdx2++;
}
nRes = ((sal_Int32) nLen1 - nNumIgnChar1) - ((sal_Int32) nLen2 - nNumIgnChar2);
}
return nRes;
}
bool DictionaryNeo::seekEntry(const OUString &rWord,
sal_Int32 *pPos, bool bSimilarOnly)
{
// look for entry with binary search.
// return sal_True if found sal_False else.
// if pPos != NULL it will become the position of the found entry, or
// if that was not found the position where it has to be inserted
// to keep the entries sorted
MutexGuard aGuard( GetLinguMutex() );
sal_Int32 nUpperIdx = getCount(),
nMidIdx,
nLowerIdx = 0;
if( nUpperIdx > 0 )
{
nUpperIdx--;
while( nLowerIdx <= nUpperIdx )
{
nMidIdx = (nLowerIdx + nUpperIdx) / 2;
DBG_ASSERT(aEntries[nMidIdx].is(), "lng : empty entry encountered");
int nCmp = - cmpDicEntry( aEntries[nMidIdx]->getDictionaryWord(),
rWord, bSimilarOnly );
if(nCmp == 0)
{
if( pPos ) *pPos = nMidIdx;
return true;
}
else if(nCmp > 0)
nLowerIdx = nMidIdx + 1;
else if( nMidIdx == 0 )
{
if( pPos ) *pPos = nLowerIdx;
return false;
}
else
nUpperIdx = nMidIdx - 1;
}
}
if( pPos ) *pPos = nLowerIdx;
return false;
}
bool DictionaryNeo::isSorted()
{
bool bRes = true;
sal_Int32 nEntries = getCount();
sal_Int32 i;
for (i = 1; i < nEntries; i++)
{
if (cmpDicEntry( aEntries[i-1]->getDictionaryWord(),
aEntries[i]->getDictionaryWord() ) > 0)
{
bRes = false;
break;
}
}
return bRes;
}
bool DictionaryNeo::addEntry_Impl(const uno::Reference< XDictionaryEntry >& xDicEntry,
bool bIsLoadEntries)
{
MutexGuard aGuard( GetLinguMutex() );
bool bRes = false;
if ( bIsLoadEntries || (!bIsReadonly && xDicEntry.is()) )
{
bool bIsNegEntry = xDicEntry->isNegative();
bool bAddEntry = !isFull() &&
( ( eDicType == DictionaryType_POSITIVE && !bIsNegEntry )
|| ( eDicType == DictionaryType_NEGATIVE && bIsNegEntry )
|| ( eDicType == DictionaryType_MIXED ) );
// look for position to insert entry at
// if there is already an entry do not insert the new one
sal_Int32 nPos = 0;
if (bAddEntry)
{
const bool bFound = seekEntry( xDicEntry->getDictionaryWord(), &nPos );
if (bFound)
bAddEntry = false;
}
if (bAddEntry)
{
DBG_ASSERT(!bNeedEntries, "lng : entries still not loaded");
// insert new entry at specified position
aEntries.insert(aEntries.begin() + nPos, xDicEntry);
SAL_WARN_IF(!isSorted(), "linguistic", "dictionary entries unsorted");
bIsModified = true;
bRes = true;
if (!bIsLoadEntries)
launchEvent( DictionaryEventFlags::ADD_ENTRY, xDicEntry );
}
}
return bRes;
}
OUString SAL_CALL DictionaryNeo::getName( )
{
MutexGuard aGuard( GetLinguMutex() );
return aDicName;
}
void SAL_CALL DictionaryNeo::setName( const OUString& aName )
{
MutexGuard aGuard( GetLinguMutex() );
if (aDicName != aName)
{
aDicName = aName;
launchEvent(DictionaryEventFlags::CHG_NAME, nullptr);
}
}
DictionaryType SAL_CALL DictionaryNeo::getDictionaryType( )
{
MutexGuard aGuard( GetLinguMutex() );
return eDicType;
}
void SAL_CALL DictionaryNeo::setActive( sal_Bool bActivate )
{
MutexGuard aGuard( GetLinguMutex() );
if (bIsActive != bool(bActivate))
{
bIsActive = bActivate;
sal_Int16 nEvent = bIsActive ?
DictionaryEventFlags::ACTIVATE_DIC : DictionaryEventFlags::DEACTIVATE_DIC;
// remove entries from memory if dictionary is deactivated
if (!bIsActive)
{
bool bIsEmpty = aEntries.empty();
// save entries first if necessary
if (bIsModified && hasLocation() && !isReadonly())
{
store();
aEntries.clear();
bNeedEntries = !bIsEmpty;
}
DBG_ASSERT( !bIsModified || !hasLocation() || isReadonly(),
"lng : dictionary is still modified" );
}
launchEvent(nEvent, nullptr);
}
}
sal_Bool SAL_CALL DictionaryNeo::isActive( )
{
MutexGuard aGuard( GetLinguMutex() );
return bIsActive;
}
sal_Int32 SAL_CALL DictionaryNeo::getCount( )
{
MutexGuard aGuard( GetLinguMutex() );
if (bNeedEntries)
loadEntries( aMainURL );
return (sal_Int32)aEntries.size();
}
Locale SAL_CALL DictionaryNeo::getLocale( )
{
MutexGuard aGuard( GetLinguMutex() );
return LanguageTag::convertToLocale( nLanguage );
}
void SAL_CALL DictionaryNeo::setLocale( const Locale& aLocale )
{
MutexGuard aGuard( GetLinguMutex() );
sal_Int16 nLanguageP = LinguLocaleToLanguage( aLocale );
if (!bIsReadonly && nLanguage != nLanguageP)
{
nLanguage = nLanguageP;
bIsModified = true; // new language needs to be saved with dictionary
launchEvent( DictionaryEventFlags::CHG_LANGUAGE, nullptr );
}
}
uno::Reference< XDictionaryEntry > SAL_CALL DictionaryNeo::getEntry(
const OUString& aWord )
{
MutexGuard aGuard( GetLinguMutex() );
if (bNeedEntries)
loadEntries( aMainURL );
sal_Int32 nPos;
bool bFound = seekEntry( aWord, &nPos, true );
DBG_ASSERT(!bFound || nPos < (sal_Int32)aEntries.size(), "lng : index out of range");
return bFound ? aEntries[ nPos ]
: uno::Reference< XDictionaryEntry >();
}
sal_Bool SAL_CALL DictionaryNeo::addEntry(
const uno::Reference< XDictionaryEntry >& xDicEntry )
{
MutexGuard aGuard( GetLinguMutex() );
bool bRes = false;
if (!bIsReadonly)
{
if (bNeedEntries)
loadEntries( aMainURL );
bRes = addEntry_Impl( xDicEntry );
}
return bRes;
}
sal_Bool SAL_CALL
DictionaryNeo::add( const OUString& rWord, sal_Bool bIsNegative,
const OUString& rRplcText )
{
MutexGuard aGuard( GetLinguMutex() );
bool bRes = false;
if (!bIsReadonly)
{
uno::Reference< XDictionaryEntry > xEntry =
new DicEntry( rWord, bIsNegative, rRplcText );
bRes = addEntry_Impl( xEntry );
}
return bRes;
}
sal_Bool SAL_CALL DictionaryNeo::remove( const OUString& aWord )
{
MutexGuard aGuard( GetLinguMutex() );
bool bRemoved = false;
if (!bIsReadonly)
{
if (bNeedEntries)
loadEntries( aMainURL );
sal_Int32 nPos;
bool bFound = seekEntry( aWord, &nPos );
DBG_ASSERT(!bFound || nPos < (sal_Int32)aEntries.size(), "lng : index out of range");
// remove element if found
if (bFound)
{
// entry to be removed
uno::Reference< XDictionaryEntry >
xDicEntry( aEntries[ nPos ] );
DBG_ASSERT(xDicEntry.is(), "lng : dictionary entry is NULL");
aEntries.erase(aEntries.begin() + nPos);
bRemoved = bIsModified = true;
launchEvent( DictionaryEventFlags::DEL_ENTRY, xDicEntry );
}
}
return bRemoved;
}
sal_Bool SAL_CALL DictionaryNeo::isFull( )
{
MutexGuard aGuard( GetLinguMutex() );
if (bNeedEntries)
loadEntries( aMainURL );
return aEntries.size() >= DIC_MAX_ENTRIES;
}
uno::Sequence< uno::Reference< XDictionaryEntry > >
SAL_CALL DictionaryNeo::getEntries( )
{
MutexGuard aGuard( GetLinguMutex() );
if (bNeedEntries)
loadEntries( aMainURL );
return comphelper::containerToSequence(aEntries);
}
void SAL_CALL DictionaryNeo::clear( )
{
MutexGuard aGuard( GetLinguMutex() );
if (!bIsReadonly && !aEntries.empty())
{
// release all references to old entries
aEntries.clear();
bNeedEntries = false;
bIsModified = true;
launchEvent( DictionaryEventFlags::ENTRIES_CLEARED , nullptr );
}
}
sal_Bool SAL_CALL DictionaryNeo::addDictionaryEventListener(
const uno::Reference< XDictionaryEventListener >& xListener )
{
MutexGuard aGuard( GetLinguMutex() );
bool bRes = false;
if (xListener.is())
{
sal_Int32 nLen = aDicEvtListeners.getLength();
bRes = aDicEvtListeners.addInterface( xListener ) != nLen;
}
return bRes;
}
sal_Bool SAL_CALL DictionaryNeo::removeDictionaryEventListener(
const uno::Reference< XDictionaryEventListener >& xListener )
{
MutexGuard aGuard( GetLinguMutex() );
bool bRes = false;
if (xListener.is())
{
sal_Int32 nLen = aDicEvtListeners.getLength();
bRes = aDicEvtListeners.removeInterface( xListener ) != nLen;
}
return bRes;
}
sal_Bool SAL_CALL DictionaryNeo::hasLocation()
{
MutexGuard aGuard( GetLinguMutex() );
return !aMainURL.isEmpty();
}
OUString SAL_CALL DictionaryNeo::getLocation()
{
MutexGuard aGuard( GetLinguMutex() );
return aMainURL;
}
sal_Bool SAL_CALL DictionaryNeo::isReadonly()
{
MutexGuard aGuard( GetLinguMutex() );
return bIsReadonly;
}
void SAL_CALL DictionaryNeo::store()
{
MutexGuard aGuard( GetLinguMutex() );
if (bIsModified && hasLocation() && !isReadonly())
{
if (!saveEntries( aMainURL ))
bIsModified = false;
}
}
void SAL_CALL DictionaryNeo::storeAsURL(
const OUString& aURL,
const uno::Sequence< beans::PropertyValue >& /*rArgs*/ )
{
MutexGuard aGuard( GetLinguMutex() );
if (!saveEntries( aURL ))
{
aMainURL = aURL;
bIsModified = false;
bIsReadonly = IsReadOnly( getLocation() );
}
}
void SAL_CALL DictionaryNeo::storeToURL(
const OUString& aURL,
const uno::Sequence< beans::PropertyValue >& /*rArgs*/ )
{
MutexGuard aGuard( GetLinguMutex() );
saveEntries(aURL);
}
DicEntry::DicEntry(const OUString &rDicFileWord,
bool bIsNegativWord)
{
if (!rDicFileWord.isEmpty())
splitDicFileWord( rDicFileWord, aDicWord, aReplacement );
bIsNegativ = bIsNegativWord;
}
DicEntry::DicEntry(const OUString &rDicWord, bool bNegativ,
const OUString &rRplcText) :
aDicWord (rDicWord),
aReplacement (rRplcText),
bIsNegativ (bNegativ)
{
}
DicEntry::~DicEntry()
{
}
void DicEntry::splitDicFileWord(const OUString &rDicFileWord,
OUString &rDicWord,
OUString &rReplacement)
{
MutexGuard aGuard( GetLinguMutex() );
sal_Int32 nDelimPos = rDicFileWord.indexOf( "==" );
if (-1 != nDelimPos)
{
sal_Int32 nTriplePos = nDelimPos + 2;
if ( nTriplePos < rDicFileWord.getLength()
&& rDicFileWord[ nTriplePos ] == '=' )
++nDelimPos;
rDicWord = rDicFileWord.copy( 0, nDelimPos );
rReplacement = rDicFileWord.copy( nDelimPos + 2 );
}
else
{
rDicWord = rDicFileWord;
rReplacement.clear();
}
}
OUString SAL_CALL DicEntry::getDictionaryWord( )
{
MutexGuard aGuard( GetLinguMutex() );
return aDicWord;
}
sal_Bool SAL_CALL DicEntry::isNegative( )
{
MutexGuard aGuard( GetLinguMutex() );
return bIsNegativ;
}
OUString SAL_CALL DicEntry::getReplacementText( )
{
MutexGuard aGuard( GetLinguMutex() );
return aReplacement;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */