20#include <com/sun/star/uno/Reference.h>
22#include <com/sun/star/linguistic2/SpellFailure.hpp>
23#include <com/sun/star/linguistic2/XLinguProperties.hpp>
28#include <com/sun/star/lang/XMultiServiceFactory.hpp>
30#include <osl/mutex.hxx>
31#include <osl/thread.h>
32#include <com/sun/star/ucb/XSimpleFileAccess.hpp>
35#include <hunspell.hxx>
41#include <svtools/strings.hrc>
44#include <osl/file.hxx>
45#include <rtl/ustrbuf.hxx>
46#include <rtl/textenc.h>
70#if !defined MAXWORDLEN
81 : m_aDName(
std::move(i_DName))
82 , m_aDLoc(
std::move(i_DLoc))
101 m_pPropHelper.reset(
new PropertyHelper_Spelling(
static_cast<XSpellChecker *
>(
this), xPropSet ) );
120 std::vector< SvtLinguConfigDictionaryEntry > aDics;
121 uno::Sequence< OUString > aFormatList;
123 "org.openoffice.lingu.MySpellSpellChecker", aFormatList );
124 for (
auto const& format : std::as_const(aFormatList))
126 std::vector< SvtLinguConfigDictionaryEntry > aTmpDic(
128 aDics.insert( aDics.end(), aTmpDic.begin(), aTmpDic.end() );
134 std::vector< SvtLinguConfigDictionaryEntry > aOldStyleDics(
145 uno::Reference< ucb::XSimpleFileAccess > xAccess(xServiceFactory->createInstance(
"com.sun.star.ucb.SimpleFileAccess"), uno::UNO_QUERY);
147 std::set<OUString> aLocaleNamesSet;
148 for (
auto const& dict : aDics)
150 const uno::Sequence< OUString > aLocaleNames( dict.aLocaleNames );
151 uno::Sequence< OUString > aLocations( dict.aLocations );
153 aLocaleNames.hasElements() && !aLocations.hasElements(),
154 "lingucomponent",
"no locations");
155 if (aLocations.hasElements())
157 if (xAccess.is() && xAccess->exists(aLocations[0]))
159 for (
auto const& locale : aLocaleNames)
164 aLocaleNamesSet.insert(locale);
171 "missing <" << aLocations[0] <<
">");
178 aLocaleNamesSet.begin(), aLocaleNamesSet.end(),
m_aSuppLocales.getArray(),
179 [](
auto const& localeName) { return LanguageTag::convertToLocale(localeName); });
186 sal_uInt32 nDictSize = std::accumulate(aDics.begin(), aDics.end(), sal_uInt32(0),
192 for (
auto const& dict : aDics)
197 const uno::Sequence< OUString > aLocaleNames( dict.
aLocaleNames );
202 for (
auto const& localeName : aLocaleNames)
208 sal_Int32
nPos = aLocation.lastIndexOf(
'.' );
209 aLocation = aLocation.copy( 0,
nPos );
237 if (rLocale == suppLocale)
251 Hunspell * pMS =
nullptr;
252 rtl_TextEncoding eEnc = RTL_TEXTENCODING_DONTKNOW;
260 OUStringBuffer rBuf(rWord);
261 sal_Int32
n = rBuf.getLength();
263 sal_Int32 extrachar = 0;
265 for (sal_Int32 ix=0; ix <
n; ix++)
268 if ((c == 0x201C) || (c == 0x201D))
270 else if ((c == 0x2018) || (c == 0x2019))
276 else if ((c == 0x200C) || (c == 0x200D) ||
277 ((c >= 0xFB00) && (c <= 0xFB04)))
280 OUString nWord(rBuf.makeStringAndClear());
287 eEnc = RTL_TEXTENCODING_DONTKNOW;
289 if (rLocale == currDict.m_aDLoc)
291 if (!currDict.m_pDict)
293 OUString dicpath = currDict.m_aDName +
".dic";
294 OUString affpath = currDict.m_aDName +
".aff";
297 osl::FileBase::getSystemPathFromFileURL(dicpath,dict);
298 osl::FileBase::getSystemPathFromFileURL(affpath,aff);
305 OString aTmpaff = Win_AddLongPathPrefix(
OUStringToOString(aff, RTL_TEXTENCODING_UTF8));
306 OString aTmpdict = Win_AddLongPathPrefix(
OUStringToOString(dict, RTL_TEXTENCODING_UTF8));
308 OString aTmpaff(
OU2ENC(aff,osl_getThreadTextEncoding()));
309 OString aTmpdict(
OU2ENC(dict,osl_getThreadTextEncoding()));
312 currDict.m_pDict = std::make_unique<Hunspell>(aTmpaff.getStr(),aTmpdict.getStr());
313#if defined(H_DEPRECATED)
319 pMS = currDict.m_pDict.get();
320 eEnc = currDict.m_aDEnc;
329 DBG_ASSERT( eEnc != RTL_TEXTENCODING_DONTKNOW,
"failed to get text encoding! (maybe incorrect encoding string in file)" );
330 if (eEnc == RTL_TEXTENCODING_DONTKNOW)
333 OString aWrd(
OU2ENC(nWord,eEnc));
334#if defined(H_DEPRECATED)
335 bool bVal = pMS->spell(std::string(aWrd), &rInfo);
337 bool bVal = pMS->spell(aWrd.getStr(), &rInfo) != 0;
340 if (extrachar && (eEnc != RTL_TEXTENCODING_UTF8)) {
341 OUStringBuffer
aBuf(nWord);
342 n =
aBuf.getLength();
343 for (sal_Int32 ix=
n-1; ix >= 0; ix--)
346 case 0xFB00:
aBuf.remove(ix, 1);
aBuf.insert(ix,
"ff");
break;
347 case 0xFB01:
aBuf.remove(ix, 1);
aBuf.insert(ix,
"fi");
break;
348 case 0xFB02:
aBuf.remove(ix, 1);
aBuf.insert(ix,
"fl");
break;
349 case 0xFB03:
aBuf.remove(ix, 1);
aBuf.insert(ix,
"ffi");
break;
350 case 0xFB04:
aBuf.remove(ix, 1);
aBuf.insert(ix,
"ffl");
break;
352 case 0x200D:
aBuf.remove(ix, 1);
break;
355 OUString aWord(
aBuf.makeStringAndClear());
356 OString bWrd(
OU2ENC(aWord, eEnc));
357#if defined(H_DEPRECATED)
358 bVal = pMS->spell(std::string(bWrd), &rInfo);
360 bVal = pMS->spell(bWrd.getStr(), &rInfo) != 0;
364 nRes = SpellFailure::SPELLING_ERROR;
377 const css::uno::Sequence< css::beans::PropertyValue >& rProperties )
381 if (rLocale ==
Locale() || rWord.isEmpty())
388 if (rWord.match(
SPELL_XML, 0) && (rWord.getLength() > 10))
return false;
397 rHelper.SetTmpPropVals( rProperties );
401 if (nFailure != -1 && !rWord.match(
SPELL_XML, 0))
405 const bool bIgnoreError =
406 (!rHelper.IsSpellUpperCase() &&
IsUpper( rWord, nLang )) ||
407 (!rHelper.IsSpellWithDigits() &&
HasDigits( rWord )) ||
408 (!rHelper.IsSpellCapitalization() && nFailure == SpellFailure::CAPTION_ERROR);
415 if ( nFailure == -1 && (nInfo & SPELL_COMPOUND) )
417 bool bHasHyphen = rWord.indexOf(
'-') > -1;
418 if ( (bHasHyphen && !rHelper.IsSpellHyphenatedCompound()) ||
419 (!bHasHyphen && !rHelper.IsSpellClosedCompound()) )
425 return (nFailure == -1);
437 Hunspell* pMS =
nullptr;
438 rtl_TextEncoding eEnc = RTL_TEXTENCODING_DONTKNOW;
441 OUStringBuffer rBuf(rWord);
442 sal_Int32
n = rBuf.getLength();
444 for (sal_Int32 ix=0; ix <
n; ix++)
447 if ((c == 0x201C) || (c == 0x201D))
449 if ((c == 0x2018) || (c == 0x2019))
452 OUString nWord(rBuf.makeStringAndClear());
463 eEnc = RTL_TEXTENCODING_DONTKNOW;
465 if (rLocale == currDict.m_aDLoc)
467 pMS = currDict.m_pDict.get();
468 eEnc = currDict.m_aDEnc;
473 OString aWrd(
OU2ENC(nWord,eEnc));
474#if defined(H_DEPRECATED)
475 std::vector<std::string> suglst = pMS->suggest(std::string(aWrd));
478 aStr.realloc(numsug + suglst.size());
479 OUString *pStr =
aStr.getArray();
480 for (
size_t ii = 0; ii < suglst.size(); ++ii)
482 OUString cvtwrd(suglst[ii].c_str(), suglst[ii].
size(), eEnc);
483 pStr[numsug + ii] = cvtwrd;
485 numsug += suglst.size();
488 char ** suglst =
nullptr;
489 int count = pMS->suggest(&suglst, aWrd.getStr());
493 OUString *pStr =
aStr.getArray();
494 for (
int ii=0; ii <
count; ++ii)
496 OUString cvtwrd(suglst[ii],strlen(suglst[ii]),eEnc);
497 pStr[numsug + ii] = cvtwrd;
501 pMS->free_list(&suglst,
count);
507 xRes = SpellAlternatives::CreateSpellAlternatives( rWord, nLang, SpellFailure::SPELLING_ERROR,
aStr );
514 const OUString& rWord,
const Locale& rLocale,
515 const css::uno::Sequence< css::beans::PropertyValue >& rProperties )
519 if (rLocale ==
Locale() || rWord.isEmpty())
526 if (!
isValid( rWord, rLocale, rProperties ))
541 bRes =
GetPropHelper().addLinguServiceEventListener( rxLstnr );
554 bRes =
GetPropHelper().removeLinguServiceEventListener( rxLstnr );
572 sal_Int32 nLen = rArguments.getLength();
576 rArguments.getConstArray()[0] >>= xPropSet;
583 m_pPropHelper.reset(
new PropertyHelper_Spelling(
static_cast<XSpellChecker *
>(
this), xPropSet ) );
587 OSL_FAIL(
"wrong number of arguments in sequence" );
598 EventObject aEvtObj(
static_cast<XSpellChecker *
>(
this) );
627 return "org.openoffice.lingu.MySpellSpellChecker";
640extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
642 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any>
const&)
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)
linguistic::PropertyHelper_Spelling & GetPropHelper_Impl()
virtual ~SpellChecker() override
virtual sal_Bool SAL_CALL addLinguServiceEventListener(const Reference< XLinguServiceEventListener > &rxLstnr) override
virtual Sequence< Locale > SAL_CALL getLocales() override
virtual void SAL_CALL initialize(const Sequence< Any > &rArguments) override
::comphelper::OInterfaceContainerHelper3< XEventListener > m_aEvtListeners
virtual sal_Bool SAL_CALL isValid(const OUString &rWord, const Locale &rLocale, const css::uno::Sequence< css::beans::PropertyValue > &rProperties) override
virtual void SAL_CALL addEventListener(const Reference< XEventListener > &rxListener) override
Reference< XSpellAlternatives > GetProposals(const OUString &rWord, const Locale &rLocale)
linguistic::PropertyHelper_Spelling & GetPropHelper()
virtual OUString SAL_CALL getServiceDisplayName(const Locale &rLocale) override
virtual sal_Bool SAL_CALL hasLocale(const Locale &rLocale) override
std::unique_ptr< linguistic::PropertyHelper_Spelling > m_pPropHelper
Sequence< Locale > m_aSuppLocales
virtual sal_Bool SAL_CALL supportsService(const OUString &rServiceName) override
virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual OUString SAL_CALL getImplementationName() override
virtual Reference< XSpellAlternatives > SAL_CALL spell(const OUString &rWord, const Locale &rLocale, const css::uno::Sequence< css::beans::PropertyValue > &rProperties) override
virtual void SAL_CALL dispose() override
virtual void SAL_CALL removeEventListener(const Reference< XEventListener > &rxListener) override
std::vector< DictItem > m_DictItems
sal_Int16 GetSpellFailure(const OUString &rWord, const Locale &rLocale, int &rInfo)
virtual sal_Bool SAL_CALL removeLinguServiceEventListener(const Reference< XLinguServiceEventListener > &rxLstnr) override
std::vector< SvtLinguConfigDictionaryEntry > GetActiveDictionariesByFormat(std::u16string_view rFormatName) const
bool GetSupportedDictionaryFormatsFor(const OUString &rSetName, const OUString &rSetEntry, css::uno::Sequence< OUString > &rFormatList) const
sal_Int32 addInterface(const css::uno::Reference< ListenerT > &rxIFace)
void disposeAndClear(const css::lang::EventObject &rEvt)
sal_Int32 removeInterface(const css::uno::Reference< ListenerT > &rxIFace)
#define DBG_ASSERT(sCon, aError)
std::vector< SvtLinguConfigDictionaryEntry > GetOldStyleDics(const char *pDicType)
void MergeNewStyleDicsAndOldStyleDics(std::vector< SvtLinguConfigDictionaryEntry > &rNewStyleDics, const std::vector< SvtLinguConfigDictionaryEntry > &rOldStyleDics)
rtl_TextEncoding getTextEncodingFromCharset(const char *pCharset)
#define OU2ENC(rtlOUString, rtlEncoding)
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
constexpr OUStringLiteral SN_SPELLCHECKER
std::locale Create(std::string_view aPrefixName, const LanguageTag &rLocale)
OUString get(TranslateId sContextAndId, const std::locale &loc)
bool isAllowlistedLanguage(const OUString &lang)
Reference< XMultiServiceFactory > getProcessServiceFactory()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
uno::Reference< XLinguProperties > GetLinguProperties()
osl::Mutex & GetLinguMutex()
bool IsUpper(const OUString &rText, sal_Int32 nPos, sal_Int32 nLen, LanguageType nLanguage)
bool HasDigits(const OUString &rText)
LanguageType LinguLocaleToLanguage(const css::lang::Locale &rLocale)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
constexpr OUStringLiteral SPELL_XML
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * lingucomponent_SpellChecker_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
DictItem(OUString i_DName, Locale i_DLoc, rtl_TextEncoding i_DEnc)
css::uno::Sequence< OUString > aLocaleNames
css::uno::Sequence< OUString > aLocations