26#include <osl/mutex.hxx>
27#include <osl/thread.h>
37#include <com/sun/star/ucb/SimpleFileAccess.hpp>
38#include <com/sun/star/linguistic2/DictionaryEventFlags.hpp>
39#include <com/sun/star/io/TempFile.hpp>
40#include <com/sun/star/io/XInputStream.hpp>
42#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
43#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
59#define VERS2_NOLANGUAGE 1024
61#define MAX_HEADER_LENGTH 16
92 uno::Reference< XLinguServiceManager2 > xRes = LinguServiceManager::create( xContext ) ;
96static bool getTag(std::string_view rLine, std::string_view rTagName,
99 size_t nPos = rLine.find(rTagName);
100 if (
nPos == std::string_view::npos)
121 sal_uInt64
const nSniffPos = rStream.
Tell();
122 static std::size_t nVerOOo7Len = sal::static_int_cast< std::size_t >(strlen(
pVerOOo7 ));
123 pMagicHeader[ nVerOOo7Len ] =
'\0';
124 if ((rStream.
ReadBytes(
static_cast<void *
>(pMagicHeader), nVerOOo7Len) == nVerOOo7Len) &&
136 while ((bSuccess = rStream.
ReadLine(aLine)))
144 if (
getTag(aLine,
"lang: ", aTagValue))
146 if (aTagValue ==
"<none>")
150 OStringToOUString( aTagValue, RTL_TEXTENCODING_ASCII_US));
154 if (
getTag(aLine,
"type: ", aTagValue))
156 bNeg = aTagValue ==
"negative";
160 if (
getTag(aLine,
"title: ", aTagValue))
162 aDicName = OStringToOUString( aTagValue, RTL_TEXTENCODING_UTF8) +
169 if (std::string_view(aLine).
find(
"---") != std::string_view::npos)
179 rStream.
Seek (nSniffPos );
186 pMagicHeader[nLen] =
'\0';
189 if (0 == strcmp( pMagicHeader,
pVerStr6 ))
191 else if (0 == strcmp( pMagicHeader,
pVerStr5 ))
193 else if (0 == strcmp( pMagicHeader,
pVerStr2 ))
219 const OUString &rMainURL,
229 bIsModified = bIsActive =
false;
230 bIsReadonly = !bWriteable;
232 if( !rMainURL.isEmpty())
244 "DictionaryNeo: dictionaries should be writeable if they are to be saved" );
246 saveEntries( rMainURL );
247 bNeedEntries =
false;
254 bNeedEntries =
false;
273 if (rMainURL.isEmpty())
279 uno::Reference< io::XInputStream >
xStream;
282 uno::Reference< ucb::XSimpleFileAccess3 > xAccess( ucb::SimpleFileAccess::create(xContext) );
283 xStream = xAccess->openFileRead( rMainURL );
285 catch (
const uno::Exception &)
287 SAL_WARN(
"linguistic",
"failed to get input stream" );
290 return ErrCode(sal_uInt32(-1));
298 ErrCode nErr = pStream->GetError();
304 eDicType = bNegativ ? DictionaryType_NEGATIVE : DictionaryType_POSITIVE;
306 rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
308 eEnc = RTL_TEXTENCODING_UTF8;
321 pStream->ReadUInt16( nLen );
326 pStream->ReadBytes(aWordBuf, nLen);
329 *(aWordBuf + nLen) = 0;
335 while(!pStream->eof())
341 OUString aText(aWordBuf, rtl_str_getLength(aWordBuf), eEnc);
342 uno::Reference< XDictionaryEntry > xEntry =
347 pStream->ReadUInt16( nLen );
355 pStream->ReadBytes(aWordBuf, nLen);
361 *(aWordBuf + nLen) = 0;
369 while (pStream->ReadLine(aLine))
371 if (aLine.isEmpty() || aLine[0] ==
'#')
373 OUString aText = OStringToOUString(aLine, RTL_TEXTENCODING_UTF8);
374 uno::Reference< XDictionaryEntry > xEntry =
387 return pStream->GetError();
390static OString
formatForSave(
const uno::Reference< XDictionaryEntry > &xEntry,
391 rtl_TextEncoding eEnc )
393 OUStringBuffer
aStr(xEntry->getDictionaryWord());
395 if (xEntry->isNegative() || !xEntry->getReplacementText().isEmpty())
397 aStr.append(
"==" + xEntry->getReplacementText());
413 uno::Reference<io::XStream>
xStream;
416 xStream = io::TempFile::create(xContext);
418 catch (
const uno::Exception &)
420 DBG_ASSERT(
false,
"failed to get input stream" );
423 return ErrCode(sal_uInt32(-1));
429 rtl_TextEncoding eEnc = RTL_TEXTENCODING_UTF8;
431 ErrCode nErr = pStream->GetError();
438 pStream->WriteLine(
"lang: <none>");
442 pStream->WriteLine(aLine);
446 if (
eDicType == DictionaryType_POSITIVE)
447 pStream->WriteLine(
"type: positive");
449 pStream->WriteLine(
"type: negative");
458 pStream->WriteLine(
"---");
464 pStream->WriteLine (aOutStr);
472 uno::Reference< ucb::XSimpleFileAccess3 > xAccess(ucb::SimpleFileAccess::create(xContext));
474 uno::Reference<io::XSeekable> xSeek(xInputStream, UNO_QUERY_THROW);
476 xAccess->writeFile(rURL, xInputStream);
481 catch (
const uno::Exception &)
483 DBG_ASSERT(
false,
"failed to write stream" );
484 return ErrCode(sal_uInt32(-1));
491 const uno::Reference< XDictionaryEntry >& xEntry)
495 DictionaryEvent aEvt;
496 aEvt.Source = uno::Reference< XDictionary >(
this );
497 aEvt.nEvent = nEvent;
498 aEvt.xDictionaryEntry = xEntry;
504 std::u16string_view rWord2,
513 sal_Int32 nLen1 = rWord1.size(),
514 nLen2 = rWord2.size();
518 if (nLen1 && cChar == rWord1[ nLen1 - 1 ])
520 if (nLen2 && cChar == rWord2[ nLen2 - 1 ])
540 while (nIdx1 < nLen1)
542 cChar1 = rWord1[ nIdx1 ];
543 if (cChar1 != cIgnChar && cChar1 != cIgnBeg && !IgnState )
545 if ( cChar1 == cIgnBeg )
547 else if (cChar1 == cIgnEnd)
553 while (nIdx2 < nLen2)
555 cChar2 = rWord2[ nIdx2 ];
556 if (cChar2 != cIgnChar && cChar2 != cIgnBeg && !IgnState )
558 if ( cChar2 == cIgnBeg )
560 else if (cChar2 == cIgnEnd)
566 if (nIdx1 < nLen1 && nIdx2 < nLen2)
568 nDiff = cChar1 - cChar2;
574 }
while (nIdx1 < nLen1 && nIdx2 < nLen2);
585 while (nIdx1 < nLen1 )
587 if (rWord1[ nIdx1 ] == cIgnBeg)
589 if (IgnState || rWord1[ nIdx1 ] == cIgnChar)
591 if (rWord1[ nIdx1] == cIgnEnd)
596 while (nIdx2 < nLen2 )
598 if (rWord2[ nIdx2 ] == cIgnBeg)
600 if (IgnState || rWord2[ nIdx2 ] == cIgnChar)
602 if (rWord2[ nIdx2 ] == cIgnEnd)
607 nRes = (nLen1 - nNumIgnChar1) - (nLen2 - nNumIgnChar2);
614 sal_Int32 *pPos,
bool bSimilarOnly)
630 while( nLowerIdx <= nUpperIdx )
632 nMidIdx = (nLowerIdx + nUpperIdx) / 2;
636 rWord, bSimilarOnly );
639 if( pPos ) *pPos = nMidIdx;
643 nLowerIdx = nMidIdx + 1;
644 else if( nMidIdx == 0 )
646 if( pPos ) *pPos = nLowerIdx;
650 nUpperIdx = nMidIdx - 1;
653 if( pPos ) *pPos = nLowerIdx;
663 for (
i = 1;
i < nEntries;
i++)
682 if ( bIsLoadEntries || (!
bIsReadonly && xDicEntry.is()) )
684 bool bIsNegEntry = xDicEntry->isNegative();
685 bool bAddEntry = !
isFull() &&
686 ( (
eDicType == DictionaryType_POSITIVE && !bIsNegEntry )
687 || (
eDicType == DictionaryType_NEGATIVE && bIsNegEntry )
688 || (
eDicType == DictionaryType_MIXED ) );
695 const bool bFound =
seekEntry( xDicEntry->getDictionaryWord(), &
nPos );
712 launchEvent( DictionaryEventFlags::ADD_ENTRY, xDicEntry );
717 if (xDicEntry.is() && !xDicEntry->isNegative() && !xDicEntry->getReplacementText().isEmpty()) {
719 uno::Reference< XSpellChecker1 > xSpell;
721 xSpell.set( xLngSvcMgr->getSpellChecker(), UNO_QUERY );
726 if (xSpell->isValid( xDicEntry->getReplacementText(),
static_cast<sal_uInt16
>(
nLanguage), aEmptySeq ))
728 xTmpRes = xSpell->spell(
"<?xml?><query type='add'><word>" +
729 xDicEntry->getDictionaryWord() +
"</word><word>" + xDicEntry->getReplacementText() +
730 "</word></query>",
static_cast<sal_uInt16
>(
nLanguage), aEmptySeq );
753 launchEvent(DictionaryEventFlags::CHG_NAME,
nullptr);
773 DictionaryEventFlags::ACTIVATE_DIC : DictionaryEventFlags::DEACTIVATE_DIC;
789 "lng : dictionary is still modified" );
807 return static_cast<sal_Int32
>(
aEntries.size());
825 launchEvent( DictionaryEventFlags::CHG_LANGUAGE,
nullptr );
830 const OUString& aWord )
842 : uno::Reference< XDictionaryEntry >();
846 const uno::Reference< XDictionaryEntry >& xDicEntry )
864 const OUString& rRplcText )
872 uno::Reference< XDictionaryEntry > xEntry =
873 new DicEntry( rWord, bIsNegative, rRplcText );
884 bool bRemoved =
false;
899 uno::Reference< XDictionaryEntry >
901 DBG_ASSERT(xDicEntry.is(),
"lng : dictionary entry is NULL");
907 launchEvent( DictionaryEventFlags::DEL_ENTRY, xDicEntry );
923uno::Sequence< uno::Reference< XDictionaryEntry > >
946 launchEvent( DictionaryEventFlags::ENTRIES_CLEARED ,
nullptr );
951 const uno::Reference< XDictionaryEventListener >& xListener )
965 const uno::Reference< XDictionaryEventListener >& xListener )
1010 const OUString& aURL,
1011 const uno::Sequence< beans::PropertyValue >& )
1024 const OUString& aURL,
1025 const uno::Sequence< beans::PropertyValue >& )
1033 bool bIsNegativWord)
1035 if (!rDicFileWord.isEmpty())
1041 OUString aRplcText_) :
1042 aDicWord (
std::move(aDicWord_)),
1043 aReplacement (
std::move(aRplcText_)),
1044 bIsNegativ (bNegativ)
1054 OUString &rReplacement)
1056 sal_Int32 nDelimPos = rDicFileWord.indexOf(
"==" );
1057 if (-1 != nDelimPos)
1059 sal_Int32 nTriplePos = nDelimPos + 2;
1060 if ( nTriplePos < rDicFileWord.getLength()
1061 && rDicFileWord[ nTriplePos ] ==
'=' )
1063 rDicWord = rDicFileWord.copy( 0, nDelimPos );
1064 rReplacement = rDicFileWord.copy( nDelimPos + 2 );
1068 rDicWord = rDicFileWord;
1069 rReplacement.clear();
virtual ~DicEntry() override
virtual sal_Bool SAL_CALL isNegative() override
DicEntry(const DicEntry &)=delete
virtual OUString SAL_CALL getDictionaryWord() override
virtual OUString SAL_CALL getReplacementText() override
static void splitDicFileWord(const OUString &rDicFileWord, OUString &rDicWord, OUString &rReplacement)
virtual sal_Bool SAL_CALL isFull() override
bool seekEntry(std::u16string_view rWord, sal_Int32 *pPos, bool bSimilarOnly=false)
static int cmpDicEntry(std::u16string_view rWord1, std::u16string_view rWord2, bool bSimilarOnly=false)
ErrCode loadEntries(const OUString &rMainURL)
virtual sal_Bool SAL_CALL addEntry(const css::uno::Reference< css::linguistic2::XDictionaryEntry > &xDicEntry) override
virtual sal_Bool SAL_CALL add(const OUString &aWord, sal_Bool bIsNegative, const OUString &aRplcText) override
virtual void SAL_CALL store() override
void launchEvent(sal_Int16 nEvent, const css::uno::Reference< css::linguistic2::XDictionaryEntry > &xEntry)
virtual OUString SAL_CALL getLocation() override
virtual css::uno::Reference< css::linguistic2::XDictionaryEntry > SAL_CALL getEntry(const OUString &aWord) override
bool addEntry_Impl(const css::uno::Reference< css::linguistic2::XDictionaryEntry > &rDicEntry, bool bIsLoadEntries=false)
virtual void SAL_CALL setActive(sal_Bool bActivate) override
virtual void SAL_CALL setLocale(const css::lang::Locale &aLocale) override
virtual sal_Bool SAL_CALL isReadonly() override
virtual sal_Bool SAL_CALL hasLocation() override
ErrCode saveEntries(const OUString &rMainURL)
virtual void SAL_CALL clear() override
virtual void SAL_CALL storeAsURL(const OUString &aURL, const css::uno::Sequence< css::beans::PropertyValue > &aArgs) override
virtual css::lang::Locale SAL_CALL getLocale() override
virtual sal_Bool SAL_CALL isActive() override
virtual void SAL_CALL setName(const OUString &aName) override
virtual sal_Bool SAL_CALL removeDictionaryEventListener(const css::uno::Reference< css::linguistic2::XDictionaryEventListener > &xListener) override
virtual css::linguistic2::DictionaryType SAL_CALL getDictionaryType() override
::comphelper::OInterfaceContainerHelper3< css::linguistic2::XDictionaryEventListener > aDicEvtListeners
virtual sal_Bool SAL_CALL remove(const OUString &aWord) override
virtual void SAL_CALL storeToURL(const OUString &aURL, const css::uno::Sequence< css::beans::PropertyValue > &aArgs) override
virtual OUString SAL_CALL getName() override
DictionaryNeo(const DictionaryNeo &)=delete
css::linguistic2::DictionaryType eDicType
std::vector< css::uno::Reference< css::linguistic2::XDictionaryEntry > > aEntries
virtual ~DictionaryNeo() override
virtual sal_Int32 SAL_CALL getCount() override
virtual sal_Bool SAL_CALL addDictionaryEventListener(const css::uno::Reference< css::linguistic2::XDictionaryEventListener > &xListener) override
virtual css::uno::Sequence< css::uno::Reference< css::linguistic2::XDictionaryEntry > > SAL_CALL getEntries() override
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)
static OUString convertToBcp47(LanguageType nLangID)
static LanguageType convertToLanguageType(const css::lang::Locale &rLocale, bool bResolveSystem=true)
SvStream & ReadCharAsBool(bool &rBool)
bool ReadLine(OStringBuffer &rStr, sal_Int32 nMaxBytesToRead=0xFFFE)
sal_uInt64 Seek(sal_uInt64 nPos)
std::size_t ReadBytes(void *pData, std::size_t nSize)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
sal_Int32 addInterface(const css::uno::Reference< ListenerT > &rxIFace)
sal_Int32 getLength() const
sal_Int32 removeInterface(const css::uno::Reference< ListenerT > &rxIFace)
void notifyEach(void(SAL_CALL ListenerT::*NotificationMethod)(const EventT &), const EventT &Event)
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
#define DBG_ASSERT(sCon, aError)
const char *const pVerOOo7
const sal_Int16 DIC_VERSION_7
static bool getTag(std::string_view rLine, std::string_view rTagName, OString &rTagValue)
static uno::Reference< XLinguServiceManager2 > GetLngSvcMgr_Impl()
const sal_Int16 DIC_VERSION_2
const sal_Int16 DIC_VERSION_6
const char *const pVerStr2
const sal_Int16 DIC_VERSION_DONTKNOW
constexpr OUStringLiteral EXTENSION_FOR_TITLE_TEXT
const char *const pVerStr6
const sal_Int16 DIC_VERSION_5
static OString formatForSave(const uno::Reference< XDictionaryEntry > &xEntry, rtl_TextEncoding eEnc)
constexpr OUStringLiteral SPELLML_SUPPORT
const char *const pVerStr5
#define MAX_HEADER_LENGTH
sal_Int16 ReadDicVersion(SvStream &rStream, LanguageType &nLng, bool &bNeg, OUString &aDicName)
#define SVSTREAM_READ_ERROR
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
OString strip(const OString &rIn, char c)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Reference< XComponentContext > getProcessComponentContext()
OSQLColumns::const_iterator find(const OSQLColumns::const_iterator &first, const OSQLColumns::const_iterator &last, std::u16string_view _rVal, const ::comphelper::UStringMixEqual &_rCase)
bool IsReadOnly(const OUString &rURL, bool *pbExist)
bool FileExists(const OUString &rMainURL)
bool LinguIsUnspecified(LanguageType nLanguage)
Checks if a LanguageType is one of the values that denote absence of language or undetermined languag...
osl::Mutex & GetLinguMutex()
! multi-thread safe mutex for all platforms !!
LanguageType LinguLocaleToLanguage(const css::lang::Locale &rLocale)
Convert Locale to LanguageType for legacy handling.
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)