Teach symstore more duplicated DLLs
[LibreOffice.git] / lingucomponent / source / hyphenator / hyphen / hyphenimp.cxx
bloba164208442283c9af2ecc1ea5bf799e5a05a1f12
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 .
20 #include <com/sun/star/uno/Reference.h>
22 #include <comphelper/sequence.hxx>
23 #include <cppuhelper/factory.hxx>
24 #include <cppuhelper/supportsservice.hxx>
25 #include <com/sun/star/registry/XRegistryKey.hpp>
26 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
27 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
28 #include <i18nlangtag/languagetag.hxx>
29 #include <tools/debug.hxx>
30 #include <osl/mutex.hxx>
31 #include <osl/thread.h>
33 #include <hyphen.h>
34 #include "hyphenimp.hxx"
36 #include <linguistic/hyphdta.hxx>
37 #include <rtl/ustring.hxx>
38 #include <rtl/ustrbuf.hxx>
39 #include <rtl/textenc.h>
40 #include <sal/log.hxx>
42 #include <linguistic/lngprops.hxx>
43 #include <linguistic/misc.hxx>
44 #include <svtools/strings.hrc>
45 #include <unotools/charclass.hxx>
46 #include <unotools/pathoptions.hxx>
47 #include <unotools/useroptions.hxx>
48 #include <unotools/lingucfg.hxx>
49 #include <unotools/resmgr.hxx>
50 #include <osl/file.hxx>
52 #include <stdio.h>
53 #include <string.h>
55 #include <cassert>
56 #include <numeric>
57 #include <vector>
58 #include <set>
59 #include <memory>
61 using namespace utl;
62 using namespace osl;
63 using namespace com::sun::star;
64 using namespace com::sun::star::beans;
65 using namespace com::sun::star::lang;
66 using namespace com::sun::star::uno;
67 using namespace com::sun::star::linguistic2;
68 using namespace linguistic;
70 Hyphenator::Hyphenator() :
71 aEvtListeners ( GetLinguMutex() )
73 bDisposing = false;
76 Hyphenator::~Hyphenator()
78 for (auto & rInfo : mvDicts)
80 if (rInfo.aPtr)
81 hnj_hyphen_free(rInfo.aPtr);
84 if (pPropHelper)
86 pPropHelper->RemoveAsPropListener();
90 PropertyHelper_Hyphenation& Hyphenator::GetPropHelper_Impl()
92 if (!pPropHelper)
94 Reference< XLinguProperties > xPropSet = GetLinguProperties();
96 pPropHelper.reset( new PropertyHelper_Hyphenation (static_cast<XHyphenator *>(this), xPropSet ) );
97 pPropHelper->AddAsPropListener(); //! after a reference is established
99 return *pPropHelper;
102 Sequence< Locale > SAL_CALL Hyphenator::getLocales()
104 MutexGuard aGuard( GetLinguMutex() );
106 // this routine should return the locales supported by the installed
107 // dictionaries.
108 if (mvDicts.empty())
110 SvtLinguConfig aLinguCfg;
112 // get list of dictionaries-to-use
113 // (or better speaking: the list of dictionaries using the
114 // new configuration entries).
115 std::vector< SvtLinguConfigDictionaryEntry > aDics;
116 uno::Sequence< OUString > aFormatList;
117 aLinguCfg.GetSupportedDictionaryFormatsFor( "Hyphenators",
118 "org.openoffice.lingu.LibHnjHyphenator", aFormatList );
119 for (const auto& rFormat : std::as_const(aFormatList))
121 std::vector< SvtLinguConfigDictionaryEntry > aTmpDic(
122 aLinguCfg.GetActiveDictionariesByFormat( rFormat ) );
123 aDics.insert( aDics.end(), aTmpDic.begin(), aTmpDic.end() );
126 //!! for compatibility with old dictionaries (the ones not using extensions
127 //!! or new configuration entries, but still using the dictionary.lst file)
128 //!! Get the list of old style spell checking dictionaries to use...
129 std::vector< SvtLinguConfigDictionaryEntry > aOldStyleDics(
130 GetOldStyleDics( "HYPH" ) );
132 // to prefer dictionaries with configuration entries we will only
133 // use those old style dictionaries that add a language that
134 // is not yet supported by the list of new style dictionaries
135 MergeNewStyleDicsAndOldStyleDics( aDics, aOldStyleDics );
137 if (!aDics.empty())
139 // get supported locales from the dictionaries-to-use...
140 std::set<OUString> aLocaleNamesSet;
141 for (auto const& dict : aDics)
143 for (const auto& rLocaleName : dict.aLocaleNames)
145 aLocaleNamesSet.insert( rLocaleName );
148 // ... and add them to the resulting sequence
149 std::vector<Locale> aLocalesVec;
150 aLocalesVec.reserve(aLocaleNamesSet.size());
152 std::transform(aLocaleNamesSet.begin(), aLocaleNamesSet.end(), std::back_inserter(aLocalesVec),
153 [](const OUString& localeName) { return LanguageTag::convertToLocale(localeName); });
155 aSuppLocales = comphelper::containerToSequence(aLocalesVec);
157 //! For each dictionary and each locale we need a separate entry.
158 //! If this results in more than one dictionary per locale than (for now)
159 //! it is undefined which dictionary gets used.
160 //! In the future the implementation should support using several dictionaries
161 //! for one locale.
162 sal_Int32 numdict = std::accumulate(aDics.begin(), aDics.end(), 0,
163 [](const sal_Int32 nSum, const SvtLinguConfigDictionaryEntry& dict) {
164 return nSum + dict.aLocaleNames.getLength(); });
166 // add dictionary information
167 mvDicts.resize(numdict);
169 sal_Int32 k = 0;
170 for (auto const& dict : aDics)
172 if (dict.aLocaleNames.hasElements() &&
173 dict.aLocations.hasElements())
175 // currently only one language per dictionary is supported in the actual implementation...
176 // Thus here we work-around this by adding the same dictionary several times.
177 // Once for each of its supported locales.
178 for (const auto& rLocaleName : dict.aLocaleNames)
180 LanguageTag aLanguageTag(rLocaleName);
181 mvDicts[k].aPtr = nullptr;
182 mvDicts[k].eEnc = RTL_TEXTENCODING_DONTKNOW;
183 mvDicts[k].aLoc = aLanguageTag.getLocale();
184 mvDicts[k].apCC.reset( new CharClass( aLanguageTag ) );
185 // also both files have to be in the same directory and the
186 // file names must only differ in the extension (.aff/.dic).
187 // Thus we use the first location only and strip the extension part.
188 OUString aLocation = dict.aLocations[0];
189 sal_Int32 nPos = aLocation.lastIndexOf( '.' );
190 aLocation = aLocation.copy( 0, nPos );
191 mvDicts[k].aName = aLocation;
193 ++k;
197 DBG_ASSERT( k == numdict, "index mismatch?" );
199 else
201 // no dictionary found so register no dictionaries
202 mvDicts.clear();
203 aSuppLocales.realloc(0);
207 return aSuppLocales;
210 sal_Bool SAL_CALL Hyphenator::hasLocale(const Locale& rLocale)
212 MutexGuard aGuard( GetLinguMutex() );
214 if (!aSuppLocales.hasElements())
215 getLocales();
217 return comphelper::findValue(aSuppLocales, rLocale) != -1;
220 namespace {
221 bool LoadDictionary(HDInfo& rDict)
223 OUString DictFN = rDict.aName + ".dic";
224 OUString dictpath;
226 osl::FileBase::getSystemPathFromFileURL(DictFN, dictpath);
228 #if defined(_WIN32)
229 // hnj_hyphen_load expects UTF-8 encoded paths with \\?\ long path prefix.
230 OString sTmp = Win_AddLongPathPrefix(OUStringToOString(dictpath, RTL_TEXTENCODING_UTF8));
231 #else
232 OString sTmp(OU2ENC(dictpath, osl_getThreadTextEncoding()));
233 #endif
234 HyphenDict *dict = nullptr;
235 if ((dict = hnj_hyphen_load(sTmp.getStr())) == nullptr)
237 SAL_WARN(
238 "lingucomponent",
239 "Couldn't find file " << dictpath);
240 return false;
242 rDict.aPtr = dict;
243 rDict.eEnc = getTextEncodingFromCharset(dict->cset);
244 return true;
248 Reference< XHyphenatedWord > SAL_CALL Hyphenator::hyphenate( const OUString& aWord,
249 const css::lang::Locale& aLocale,
250 sal_Int16 nMaxLeading,
251 const css::uno::Sequence< css::beans::PropertyValue >& aProperties )
253 PropertyHelper_Hyphenation& rHelper = GetPropHelper();
254 rHelper.SetTmpPropVals(aProperties);
255 sal_Int16 minTrail = rHelper.GetMinTrailing();
256 sal_Int16 minLead = rHelper.GetMinLeading();
257 sal_Int16 minLen = rHelper.GetMinWordLength();
258 bool bNoHyphenateCaps = rHelper.IsNoHyphenateCaps();
260 HyphenDict *dict = nullptr;
261 rtl_TextEncoding eEnc = RTL_TEXTENCODING_DONTKNOW;
263 Reference< XHyphenatedWord > xRes;
265 int k = -1;
266 for (size_t j = 0; j < mvDicts.size(); ++j)
268 if (aLocale == mvDicts[j].aLoc)
269 k = j;
272 // if we have a hyphenation dictionary matching this locale
273 if (k != -1)
275 int nHyphenationPos = -1;
276 int nHyphenationPosAlt = -1;
277 int nHyphenationPosAltHyph = -1;
279 // if this dictionary has not been loaded yet do that
280 if (!mvDicts[k].aPtr)
282 if (!LoadDictionary(mvDicts[k]))
283 return nullptr;
286 // otherwise hyphenate the word with that dictionary
287 dict = mvDicts[k].aPtr;
288 eEnc = mvDicts[k].eEnc;
289 CharClass * pCC = mvDicts[k].apCC.get();
291 // Don't hyphenate uppercase words if requested
292 if (bNoHyphenateCaps && aWord == makeUpperCase(aWord, pCC))
294 return nullptr;
297 // we don't want to work with a default text encoding since following incorrect
298 // results may occur only for specific text and thus may be hard to notice.
299 // Thus better always make a clean exit here if the text encoding is in question.
300 // Hopefully something not working at all will raise proper attention quickly. ;-)
301 DBG_ASSERT( eEnc != RTL_TEXTENCODING_DONTKNOW, "failed to get text encoding! (maybe incorrect encoding string in file)" );
302 if (eEnc == RTL_TEXTENCODING_DONTKNOW)
303 return nullptr;
305 CapType ct = capitalType(aWord, pCC);
307 // first convert any smart quotes or apostrophes to normal ones
308 OUStringBuffer rBuf(aWord);
309 sal_Int32 nc = rBuf.getLength();
310 sal_Unicode ch;
311 for (sal_Int32 ix=0; ix < nc; ix++)
313 ch = rBuf[ix];
314 if ((ch == 0x201C) || (ch == 0x201D))
315 rBuf[ix] = u'"';
316 if ((ch == 0x2018) || (ch == 0x2019))
317 rBuf[ix] = u'\'';
319 OUString nWord(rBuf.makeStringAndClear());
321 // now convert word to all lowercase for pattern recognition
322 OUString nTerm(makeLowerCase(nWord, pCC));
324 // now convert word to needed encoding
325 OString encWord(OU2ENC(nTerm,eEnc));
327 int wordlen = encWord.getLength();
328 std::unique_ptr<char[]> lcword(new char[wordlen + 1]);
329 std::unique_ptr<char[]> hyphens(new char[wordlen + 5]);
331 char ** rep = nullptr; // replacements of discretionary hyphenation
332 int * pos = nullptr; // array of [hyphenation point] minus [deletion position]
333 int * cut = nullptr; // length of deletions in original word
335 // copy converted word into simple char buffer
336 strcpy(lcword.get(),encWord.getStr());
338 // now strip off any ending periods
339 int n = wordlen-1;
340 while((n >=0) && (lcword[n] == '.'))
341 n--;
342 n++;
343 if (n > 0)
345 const bool bFailed = 0 != hnj_hyphen_hyphenate3( dict, lcword.get(), n, hyphens.get(), nullptr,
346 &rep, &pos, &cut, minLead, minTrail,
347 std::max<sal_Int16>(dict->clhmin, std::max<sal_Int16>(dict->clhmin, 2) + std::max(0, minLead - std::max<sal_Int16>(dict->lhmin, 2))),
348 std::max<sal_Int16>(dict->crhmin, std::max<sal_Int16>(dict->crhmin, 2) + std::max(0, minTrail - std::max<sal_Int16>(dict->rhmin, 2))) );
349 if (bFailed)
351 // whoops something did not work
352 if (rep)
354 for(int j = 0; j < n; j++)
356 if (rep[j]) free(rep[j]);
358 free(rep);
360 if (pos) free(pos);
361 if (cut) free(cut);
362 return nullptr;
366 // now backfill hyphens[] for any removed trailing periods
367 for (int c = n; c < wordlen; c++) hyphens[c] = '0';
368 hyphens[wordlen] = '\0';
370 sal_Int32 Leading = GetPosInWordToCheck( aWord, nMaxLeading );
372 for (sal_Int32 i = 0; i < n; i++)
374 int leftrep = 0;
375 bool hit = (n >= minLen);
376 if (!rep || !rep[i])
378 hit = hit && (hyphens[i]&1) && (i < Leading);
379 hit = hit && (i >= (minLead-1) );
380 hit = hit && ((n - i - 1) >= minTrail);
382 else
384 // calculate change character length before hyphenation point signed with '='
385 for (char * c = rep[i]; *c && (*c != '='); c++)
387 if (eEnc == RTL_TEXTENCODING_UTF8)
389 if (static_cast<unsigned char>(*c) >> 6 != 2)
390 leftrep++;
392 else
393 leftrep++;
395 hit = hit && (hyphens[i]&1) && ((i + leftrep - pos[i]) < Leading);
396 hit = hit && ((i + leftrep - pos[i]) >= (minLead-1) );
397 hit = hit && ((n - i - 1 + sal::static_int_cast< sal_sSize >(strlen(rep[i])) - leftrep - 1) >= minTrail);
399 if (hit)
401 nHyphenationPos = i;
402 if (rep && rep[i])
404 nHyphenationPosAlt = i - pos[i];
405 nHyphenationPosAltHyph = i + leftrep - pos[i];
410 if (nHyphenationPos == -1)
412 xRes = nullptr;
414 else
416 if (rep && rep[nHyphenationPos])
418 // remove equal sign
419 char * s = rep[nHyphenationPos];
420 int eq = 0;
421 for (; *s; s++)
423 if (*s == '=') eq = 1;
424 if (eq) *s = *(s + 1);
426 OUString repHyphlow(rep[nHyphenationPos], strlen(rep[nHyphenationPos]), eEnc);
427 OUString repHyph;
428 switch (ct)
430 case CapType::ALLCAP:
432 repHyph = makeUpperCase(repHyphlow, pCC);
433 break;
435 case CapType::INITCAP:
437 if (nHyphenationPosAlt == -1)
438 repHyph = makeInitCap(repHyphlow, pCC);
439 else
440 repHyph = repHyphlow;
441 break;
443 default:
445 repHyph = repHyphlow;
446 break;
450 // handle shortening
451 sal_Int16 nPos = static_cast<sal_Int16>((nHyphenationPosAltHyph < nHyphenationPos) ?
452 nHyphenationPosAltHyph : nHyphenationPos);
453 // discretionary hyphenation
454 xRes = HyphenatedWord::CreateHyphenatedWord( aWord, LinguLocaleToLanguage( aLocale ), nPos,
455 aWord.replaceAt(nHyphenationPosAlt + 1, cut[nHyphenationPos], repHyph),
456 static_cast<sal_Int16>(nHyphenationPosAltHyph));
458 else
460 xRes = HyphenatedWord::CreateHyphenatedWord( aWord, LinguLocaleToLanguage( aLocale ),
461 static_cast<sal_Int16>(nHyphenationPos), aWord, static_cast<sal_Int16>(nHyphenationPos));
465 if (rep)
467 for(int j = 0; j < n; j++)
469 if (rep[j]) free(rep[j]);
471 free(rep);
473 if (pos) free(pos);
474 if (cut) free(cut);
475 return xRes;
477 return nullptr;
480 Reference < XHyphenatedWord > SAL_CALL Hyphenator::queryAlternativeSpelling(
481 const OUString& aWord,
482 const css::lang::Locale& aLocale,
483 sal_Int16 nIndex,
484 const css::uno::Sequence< css::beans::PropertyValue >& aProperties )
486 // Firstly we allow only one plus character before the hyphen to avoid to miss the right break point:
487 for (int extrachar = 1; extrachar <= 2; extrachar++)
489 Reference< XHyphenatedWord > xRes = hyphenate(aWord, aLocale, nIndex + 1 + extrachar, aProperties);
490 if (xRes.is() && xRes->isAlternativeSpelling() && xRes->getHyphenationPos() == nIndex)
491 return xRes;
493 return nullptr;
496 Reference< XPossibleHyphens > SAL_CALL Hyphenator::createPossibleHyphens( const OUString& aWord,
497 const css::lang::Locale& aLocale,
498 const css::uno::Sequence< css::beans::PropertyValue >& aProperties )
500 PropertyHelper_Hyphenation& rHelper = GetPropHelper();
501 rHelper.SetTmpPropVals(aProperties);
502 sal_Int16 minTrail = rHelper.GetMinTrailing();
503 sal_Int16 minLead = rHelper.GetMinLeading();
504 sal_Int16 minLen = rHelper.GetMinWordLength();
506 // Resolves: fdo#41083 honour MinWordLength in "createPossibleHyphens" as
507 // well as "hyphenate"
508 if (aWord.getLength() < minLen)
510 return PossibleHyphens::CreatePossibleHyphens( aWord, LinguLocaleToLanguage( aLocale ),
511 aWord, Sequence< sal_Int16 >() );
514 int k = -1;
515 for (size_t j = 0; j < mvDicts.size(); ++j)
517 if (aLocale == mvDicts[j].aLoc)
518 k = j;
521 // if we have a hyphenation dictionary matching this locale
522 if (k != -1)
524 HyphenDict *dict = nullptr;
525 // if this dictionary has not been loaded yet do that
526 if (!mvDicts[k].aPtr)
528 if (!LoadDictionary(mvDicts[k]))
529 return nullptr;
532 // otherwise hyphenate the word with that dictionary
533 dict = mvDicts[k].aPtr;
534 rtl_TextEncoding eEnc = mvDicts[k].eEnc;
535 CharClass* pCC = mvDicts[k].apCC.get();
537 // we don't want to work with a default text encoding since following incorrect
538 // results may occur only for specific text and thus may be hard to notice.
539 // Thus better always make a clean exit here if the text encoding is in question.
540 // Hopefully something not working at all will raise proper attention quickly. ;-)
541 DBG_ASSERT( eEnc != RTL_TEXTENCODING_DONTKNOW, "failed to get text encoding! (maybe incorrect encoding string in file)" );
542 if (eEnc == RTL_TEXTENCODING_DONTKNOW)
543 return nullptr;
545 // first handle smart quotes both single and double
546 OUStringBuffer rBuf(aWord);
547 sal_Int32 nc = rBuf.getLength();
548 sal_Unicode ch;
549 for (sal_Int32 ix=0; ix < nc; ix++)
551 ch = rBuf[ix];
552 if ((ch == 0x201C) || (ch == 0x201D))
553 rBuf[ix] = u'"';
554 if ((ch == 0x2018) || (ch == 0x2019))
555 rBuf[ix] = u'\'';
557 OUString nWord(rBuf.makeStringAndClear());
559 // now convert word to all lowercase for pattern recognition
560 OUString nTerm(makeLowerCase(nWord, pCC));
562 // now convert word to needed encoding
563 OString encWord(OU2ENC(nTerm,eEnc));
565 sal_Int32 wordlen = encWord.getLength();
566 std::unique_ptr<char[]> lcword(new char[wordlen+1]);
567 std::unique_ptr<char[]> hyphens(new char[wordlen+5]);
568 char ** rep = nullptr; // replacements of discretionary hyphenation
569 int * pos = nullptr; // array of [hyphenation point] minus [deletion position]
570 int * cut = nullptr; // length of deletions in original word
572 // copy converted word into simple char buffer
573 strcpy(lcword.get(),encWord.getStr());
575 // first remove any trailing periods
576 sal_Int32 n = wordlen-1;
577 while((n >=0) && (lcword[n] == '.'))
578 n--;
579 n++;
580 if (n > 0)
582 const bool bFailed = 0 != hnj_hyphen_hyphenate3(dict, lcword.get(), n, hyphens.get(), nullptr,
583 &rep, &pos, &cut, minLead, minTrail,
584 std::max<sal_Int16>(dict->clhmin, std::max<sal_Int16>(dict->clhmin, 2) + std::max(0, minLead - std::max<sal_Int16>(dict->lhmin, 2))),
585 std::max<sal_Int16>(dict->crhmin, std::max<sal_Int16>(dict->crhmin, 2) + std::max(0, minTrail - std::max<sal_Int16>(dict->rhmin, 2))) );
586 if (bFailed)
588 if (rep)
590 for(int j = 0; j < n; j++)
592 if (rep[j]) free(rep[j]);
594 free(rep);
596 if (pos) free(pos);
597 if (cut) free(cut);
599 return nullptr;
602 // now backfill hyphens[] for any removed periods
603 for (sal_Int32 c = n; c < wordlen; c++)
604 hyphens[c] = '0';
605 hyphens[wordlen] = '\0';
607 sal_Int32 nHyphCount = 0;
609 for ( sal_Int32 i = 0; i < encWord.getLength(); i++)
611 if (hyphens[i]&1)
612 nHyphCount++;
615 Sequence< sal_Int16 > aHyphPos(nHyphCount);
616 sal_Int16 *pPos = aHyphPos.getArray();
617 OUStringBuffer hyphenatedWordBuffer;
618 nHyphCount = 0;
620 for (sal_Int32 i = 0; i < nWord.getLength(); i++)
622 hyphenatedWordBuffer.append(aWord[i]);
623 // hyphenation position
624 if (hyphens[i]&1)
626 // linguistic::PossibleHyphens is stuck with
627 // css::uno::Sequence<sal_Int16> because of
628 // css.linguistic2.XPossibleHyphens.getHyphenationPositions, so
629 // any further positions need to be ignored:
630 assert(i >= SAL_MIN_INT16);
631 if (i > SAL_MAX_INT16)
633 SAL_WARN(
634 "lingucomponent",
635 "hyphen pos " << i << " > SAL_MAX_INT16 in \"" << aWord
636 << "\"");
637 continue;
639 pPos[nHyphCount] = i;
640 hyphenatedWordBuffer.append('=');
641 nHyphCount++;
645 OUString hyphenatedWord = hyphenatedWordBuffer.makeStringAndClear();
647 Reference< XPossibleHyphens > xRes = PossibleHyphens::CreatePossibleHyphens(
648 aWord, LinguLocaleToLanguage( aLocale ), hyphenatedWord, aHyphPos);
650 if (rep)
652 for(int j = 0; j < n; j++)
654 if (rep[j]) free(rep[j]);
656 free(rep);
658 if (pos) free(pos);
659 if (cut) free(cut);
661 return xRes;
664 return nullptr;
667 OUString Hyphenator::makeLowerCase(const OUString& aTerm, CharClass const * pCC)
669 if (pCC)
670 return pCC->lowercase(aTerm);
671 return aTerm;
674 OUString Hyphenator::makeUpperCase(const OUString& aTerm, CharClass const * pCC)
676 if (pCC)
677 return pCC->uppercase(aTerm);
678 return aTerm;
681 OUString Hyphenator::makeInitCap(const OUString& aTerm, CharClass const * pCC)
683 sal_Int32 tlen = aTerm.getLength();
684 if (pCC && tlen)
686 OUString bTemp = aTerm.copy(0,1);
687 if (tlen > 1)
688 return ( pCC->uppercase(bTemp, 0, 1) + pCC->lowercase(aTerm,1,(tlen-1)) );
690 return pCC->uppercase(bTemp, 0, 1);
692 return aTerm;
695 /// @throws Exception
696 static Reference< XInterface > Hyphenator_CreateInstance(
697 const Reference< XMultiServiceFactory > & /*rSMgr*/ )
699 Reference< XInterface > xService = static_cast<cppu::OWeakObject*>(new Hyphenator);
700 return xService;
703 sal_Bool SAL_CALL Hyphenator::addLinguServiceEventListener(
704 const Reference< XLinguServiceEventListener >& rxLstnr )
706 MutexGuard aGuard( GetLinguMutex() );
708 bool bRes = false;
709 if (!bDisposing && rxLstnr.is())
711 bRes = GetPropHelper().addLinguServiceEventListener( rxLstnr );
713 return bRes;
716 sal_Bool SAL_CALL Hyphenator::removeLinguServiceEventListener(
717 const Reference< XLinguServiceEventListener >& rxLstnr )
719 MutexGuard aGuard( GetLinguMutex() );
721 bool bRes = false;
722 if (!bDisposing && rxLstnr.is())
724 bRes = GetPropHelper().removeLinguServiceEventListener( rxLstnr );
726 return bRes;
729 OUString SAL_CALL Hyphenator::getServiceDisplayName(const Locale& rLocale)
731 std::locale loc(Translate::Create("svt", LanguageTag(rLocale)));
732 return Translate::get(STR_DESCRIPTION_LIBHYPHEN, loc);
735 void SAL_CALL Hyphenator::initialize( const Sequence< Any >& rArguments )
737 MutexGuard aGuard( GetLinguMutex() );
739 if (!pPropHelper)
741 sal_Int32 nLen = rArguments.getLength();
742 if (2 == nLen)
744 Reference< XLinguProperties > xPropSet;
745 rArguments.getConstArray()[0] >>= xPropSet;
746 // rArguments.getConstArray()[1] >>= xDicList;
748 //! Pointer allows for access of the non-UNO functions.
749 //! And the reference to the UNO-functions while increasing
750 //! the ref-count and will implicitly free the memory
751 //! when the object is no longer used.
752 pPropHelper.reset( new PropertyHelper_Hyphenation( static_cast<XHyphenator *>(this), xPropSet ) );
753 pPropHelper->AddAsPropListener(); //! after a reference is established
755 else {
756 OSL_FAIL( "wrong number of arguments in sequence" );
761 void SAL_CALL Hyphenator::dispose()
763 MutexGuard aGuard( GetLinguMutex() );
765 if (!bDisposing)
767 bDisposing = true;
768 EventObject aEvtObj( static_cast<XHyphenator *>(this) );
769 aEvtListeners.disposeAndClear( aEvtObj );
770 if (pPropHelper)
772 pPropHelper->RemoveAsPropListener();
773 pPropHelper.reset();
778 void SAL_CALL Hyphenator::addEventListener( const Reference< XEventListener >& rxListener )
780 MutexGuard aGuard( GetLinguMutex() );
782 if (!bDisposing && rxListener.is())
783 aEvtListeners.addInterface( rxListener );
786 void SAL_CALL Hyphenator::removeEventListener( const Reference< XEventListener >& rxListener )
788 MutexGuard aGuard( GetLinguMutex() );
790 if (!bDisposing && rxListener.is())
791 aEvtListeners.removeInterface( rxListener );
794 // Service specific part
795 OUString SAL_CALL Hyphenator::getImplementationName()
797 return getImplementationName_Static();
800 sal_Bool SAL_CALL Hyphenator::supportsService( const OUString& ServiceName )
802 return cppu::supportsService(this, ServiceName);
805 Sequence< OUString > SAL_CALL Hyphenator::getSupportedServiceNames()
807 return getSupportedServiceNames_Static();
810 Sequence< OUString > Hyphenator::getSupportedServiceNames_Static()
811 throw()
813 Sequence< OUString > aSNS { SN_HYPHENATOR };
814 return aSNS;
817 extern "C"
820 SAL_DLLPUBLIC_EXPORT void * hyphen_component_getFactory(
821 const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
823 void * pRet = nullptr;
824 if ( Hyphenator::getImplementationName_Static().equalsAscii( pImplName ) )
826 Reference< XSingleServiceFactory > xFactory =
827 cppu::createOneInstanceFactory(
828 static_cast< XMultiServiceFactory * >( pServiceManager ),
829 Hyphenator::getImplementationName_Static(),
830 Hyphenator_CreateInstance,
831 Hyphenator::getSupportedServiceNames_Static());
832 // acquire, because we return an interface pointer instead of a reference
833 xFactory->acquire();
834 pRet = xFactory.get();
836 return pRet;
840 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */