1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_linguistic.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir 32*cdf0e10cSrcweir #include <cppuhelper/factory.hxx> // helper for factories 33*cdf0e10cSrcweir #include <com/sun/star/registry/XRegistryKey.hpp> 34*cdf0e10cSrcweir #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> 35*cdf0e10cSrcweir #include <com/sun/star/linguistic2/XHyphenatedWord.hpp> 36*cdf0e10cSrcweir #include <rtl/ustrbuf.hxx> 37*cdf0e10cSrcweir #include <i18npool/lang.h> 38*cdf0e10cSrcweir #include <unotools/localedatawrapper.hxx> 39*cdf0e10cSrcweir #include <tools/debug.hxx> 40*cdf0e10cSrcweir #include <svl/lngmisc.hxx> 41*cdf0e10cSrcweir #include <unotools/processfactory.hxx> 42*cdf0e10cSrcweir #include <osl/mutex.hxx> 43*cdf0e10cSrcweir 44*cdf0e10cSrcweir #include "hyphdsp.hxx" 45*cdf0e10cSrcweir #include "linguistic/hyphdta.hxx" 46*cdf0e10cSrcweir #include "linguistic/lngprops.hxx" 47*cdf0e10cSrcweir #include "lngsvcmgr.hxx" 48*cdf0e10cSrcweir 49*cdf0e10cSrcweir 50*cdf0e10cSrcweir using namespace utl; 51*cdf0e10cSrcweir using namespace osl; 52*cdf0e10cSrcweir using namespace rtl; 53*cdf0e10cSrcweir using namespace com::sun::star; 54*cdf0e10cSrcweir using namespace com::sun::star::beans; 55*cdf0e10cSrcweir using namespace com::sun::star::lang; 56*cdf0e10cSrcweir using namespace com::sun::star::uno; 57*cdf0e10cSrcweir using namespace com::sun::star::linguistic2; 58*cdf0e10cSrcweir using namespace linguistic; 59*cdf0e10cSrcweir 60*cdf0e10cSrcweir /////////////////////////////////////////////////////////////////////////// 61*cdf0e10cSrcweir 62*cdf0e10cSrcweir HyphenatorDispatcher::HyphenatorDispatcher( LngSvcMgr &rLngSvcMgr ) : 63*cdf0e10cSrcweir rMgr (rLngSvcMgr) 64*cdf0e10cSrcweir { 65*cdf0e10cSrcweir } 66*cdf0e10cSrcweir 67*cdf0e10cSrcweir 68*cdf0e10cSrcweir HyphenatorDispatcher::~HyphenatorDispatcher() 69*cdf0e10cSrcweir { 70*cdf0e10cSrcweir ClearSvcList(); 71*cdf0e10cSrcweir } 72*cdf0e10cSrcweir 73*cdf0e10cSrcweir 74*cdf0e10cSrcweir void HyphenatorDispatcher::ClearSvcList() 75*cdf0e10cSrcweir { 76*cdf0e10cSrcweir // release memory for each table entry 77*cdf0e10cSrcweir HyphSvcByLangMap_t aTmp; 78*cdf0e10cSrcweir aSvcMap.swap( aTmp ); 79*cdf0e10cSrcweir } 80*cdf0e10cSrcweir 81*cdf0e10cSrcweir 82*cdf0e10cSrcweir Reference<XHyphenatedWord> HyphenatorDispatcher::buildHyphWord( 83*cdf0e10cSrcweir const OUString rOrigWord, 84*cdf0e10cSrcweir const Reference<XDictionaryEntry> &xEntry, 85*cdf0e10cSrcweir sal_Int16 nLang, sal_Int16 nMaxLeading ) 86*cdf0e10cSrcweir { 87*cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 88*cdf0e10cSrcweir 89*cdf0e10cSrcweir Reference< XHyphenatedWord > xRes; 90*cdf0e10cSrcweir 91*cdf0e10cSrcweir if (xEntry.is()) 92*cdf0e10cSrcweir { 93*cdf0e10cSrcweir OUString aText( xEntry->getDictionaryWord() ); 94*cdf0e10cSrcweir sal_Int32 nTextLen = aText.getLength(); 95*cdf0e10cSrcweir 96*cdf0e10cSrcweir // trailing '=' means "hyphenation should not be possible" 97*cdf0e10cSrcweir if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=') 98*cdf0e10cSrcweir { 99*cdf0e10cSrcweir sal_Int16 nHyphenationPos = -1; 100*cdf0e10cSrcweir 101*cdf0e10cSrcweir OUStringBuffer aTmp( nTextLen ); 102*cdf0e10cSrcweir sal_Bool bSkip = sal_False; 103*cdf0e10cSrcweir sal_Int32 nHyphIdx = -1; 104*cdf0e10cSrcweir sal_Int32 nLeading = 0; 105*cdf0e10cSrcweir for (sal_Int32 i = 0; i < nTextLen; i++) 106*cdf0e10cSrcweir { 107*cdf0e10cSrcweir sal_Unicode cTmp = aText[i]; 108*cdf0e10cSrcweir if (cTmp != '=') 109*cdf0e10cSrcweir { 110*cdf0e10cSrcweir aTmp.append( cTmp ); 111*cdf0e10cSrcweir nLeading++; 112*cdf0e10cSrcweir bSkip = sal_False; 113*cdf0e10cSrcweir nHyphIdx++; 114*cdf0e10cSrcweir } 115*cdf0e10cSrcweir else 116*cdf0e10cSrcweir { 117*cdf0e10cSrcweir if (!bSkip && nHyphIdx >= 0) 118*cdf0e10cSrcweir { 119*cdf0e10cSrcweir if (nLeading <= nMaxLeading) 120*cdf0e10cSrcweir nHyphenationPos = (sal_Int16) nHyphIdx; 121*cdf0e10cSrcweir } 122*cdf0e10cSrcweir bSkip = sal_True; //! multiple '=' should count as one only 123*cdf0e10cSrcweir } 124*cdf0e10cSrcweir } 125*cdf0e10cSrcweir 126*cdf0e10cSrcweir if (nHyphenationPos > 0) 127*cdf0e10cSrcweir { 128*cdf0e10cSrcweir aText = aTmp.makeStringAndClear(); 129*cdf0e10cSrcweir 130*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 131*cdf0e10cSrcweir { 132*cdf0e10cSrcweir if (aText != rOrigWord) 133*cdf0e10cSrcweir { 134*cdf0e10cSrcweir // both words should only differ by a having a trailing '.' 135*cdf0e10cSrcweir // character or not... 136*cdf0e10cSrcweir OUString aShorter, aLonger; 137*cdf0e10cSrcweir if (aText.getLength() <= rOrigWord.getLength()) 138*cdf0e10cSrcweir { 139*cdf0e10cSrcweir aShorter = aText; 140*cdf0e10cSrcweir aLonger = rOrigWord; 141*cdf0e10cSrcweir } 142*cdf0e10cSrcweir else 143*cdf0e10cSrcweir { 144*cdf0e10cSrcweir aShorter = rOrigWord; 145*cdf0e10cSrcweir aLonger = aText; 146*cdf0e10cSrcweir } 147*cdf0e10cSrcweir xub_StrLen nS = sal::static_int_cast< xub_StrLen >( aShorter.getLength() ); 148*cdf0e10cSrcweir xub_StrLen nL = sal::static_int_cast< xub_StrLen >( aLonger.getLength() ); 149*cdf0e10cSrcweir if (nS > 0 && nL > 0) 150*cdf0e10cSrcweir { 151*cdf0e10cSrcweir DBG_ASSERT( (nS + 1 == nL) && aLonger[nL-1] == (sal_Unicode) '.', 152*cdf0e10cSrcweir "HyphenatorDispatcher::buildHyphWord: unexpected difference between words!" ); 153*cdf0e10cSrcweir } 154*cdf0e10cSrcweir } 155*cdf0e10cSrcweir } 156*cdf0e10cSrcweir #endif 157*cdf0e10cSrcweir //! take care of #i22591# 158*cdf0e10cSrcweir aText = rOrigWord; 159*cdf0e10cSrcweir 160*cdf0e10cSrcweir DBG_ASSERT( aText == rOrigWord, "failed to " ); 161*cdf0e10cSrcweir xRes = new HyphenatedWord( aText, nLang, nHyphenationPos, 162*cdf0e10cSrcweir aText, nHyphenationPos ); 163*cdf0e10cSrcweir } 164*cdf0e10cSrcweir } 165*cdf0e10cSrcweir } 166*cdf0e10cSrcweir 167*cdf0e10cSrcweir return xRes; 168*cdf0e10cSrcweir } 169*cdf0e10cSrcweir 170*cdf0e10cSrcweir 171*cdf0e10cSrcweir Reference< XPossibleHyphens > HyphenatorDispatcher::buildPossHyphens( 172*cdf0e10cSrcweir const Reference< XDictionaryEntry > &xEntry, sal_Int16 nLanguage ) 173*cdf0e10cSrcweir { 174*cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 175*cdf0e10cSrcweir 176*cdf0e10cSrcweir Reference<XPossibleHyphens> xRes; 177*cdf0e10cSrcweir 178*cdf0e10cSrcweir if (xEntry.is()) 179*cdf0e10cSrcweir { 180*cdf0e10cSrcweir // text with hyphenation info 181*cdf0e10cSrcweir OUString aText( xEntry->getDictionaryWord() ); 182*cdf0e10cSrcweir sal_Int32 nTextLen = aText.getLength(); 183*cdf0e10cSrcweir 184*cdf0e10cSrcweir // trailing '=' means "hyphenation should not be possible" 185*cdf0e10cSrcweir if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=') 186*cdf0e10cSrcweir { 187*cdf0e10cSrcweir // sequence to hold hyphenation positions 188*cdf0e10cSrcweir Sequence< sal_Int16 > aHyphPos( nTextLen ); 189*cdf0e10cSrcweir sal_Int16 *pPos = aHyphPos.getArray(); 190*cdf0e10cSrcweir sal_Int32 nHyphCount = 0; 191*cdf0e10cSrcweir 192*cdf0e10cSrcweir OUStringBuffer aTmp( nTextLen ); 193*cdf0e10cSrcweir sal_Bool bSkip = sal_False; 194*cdf0e10cSrcweir sal_Int32 nHyphIdx = -1; 195*cdf0e10cSrcweir for (sal_Int32 i = 0; i < nTextLen; i++) 196*cdf0e10cSrcweir { 197*cdf0e10cSrcweir sal_Unicode cTmp = aText[i]; 198*cdf0e10cSrcweir if (cTmp != '=') 199*cdf0e10cSrcweir { 200*cdf0e10cSrcweir aTmp.append( cTmp ); 201*cdf0e10cSrcweir bSkip = sal_False; 202*cdf0e10cSrcweir nHyphIdx++; 203*cdf0e10cSrcweir } 204*cdf0e10cSrcweir else 205*cdf0e10cSrcweir { 206*cdf0e10cSrcweir if (!bSkip && nHyphIdx >= 0) 207*cdf0e10cSrcweir pPos[ nHyphCount++ ] = (sal_Int16) nHyphIdx; 208*cdf0e10cSrcweir bSkip = sal_True; //! multiple '=' should count as one only 209*cdf0e10cSrcweir } 210*cdf0e10cSrcweir } 211*cdf0e10cSrcweir 212*cdf0e10cSrcweir // ignore (multiple) trailing '=' 213*cdf0e10cSrcweir if (bSkip && nHyphIdx >= 0) 214*cdf0e10cSrcweir { 215*cdf0e10cSrcweir nHyphCount--; 216*cdf0e10cSrcweir } 217*cdf0e10cSrcweir DBG_ASSERT( nHyphCount >= 0, "lng : invalid hyphenation count"); 218*cdf0e10cSrcweir 219*cdf0e10cSrcweir if (nHyphCount > 0) 220*cdf0e10cSrcweir { 221*cdf0e10cSrcweir aHyphPos.realloc( nHyphCount ); 222*cdf0e10cSrcweir xRes = new PossibleHyphens( aTmp.makeStringAndClear(), nLanguage, 223*cdf0e10cSrcweir aText, aHyphPos ); 224*cdf0e10cSrcweir } 225*cdf0e10cSrcweir } 226*cdf0e10cSrcweir } 227*cdf0e10cSrcweir 228*cdf0e10cSrcweir return xRes; 229*cdf0e10cSrcweir } 230*cdf0e10cSrcweir 231*cdf0e10cSrcweir 232*cdf0e10cSrcweir Sequence< Locale > SAL_CALL HyphenatorDispatcher::getLocales() 233*cdf0e10cSrcweir throw(RuntimeException) 234*cdf0e10cSrcweir { 235*cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 236*cdf0e10cSrcweir 237*cdf0e10cSrcweir Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) ); 238*cdf0e10cSrcweir Locale *pLocales = aLocales.getArray(); 239*cdf0e10cSrcweir HyphSvcByLangMap_t::const_iterator aIt; 240*cdf0e10cSrcweir for (aIt = aSvcMap.begin(); aIt != aSvcMap.end(); ++aIt) 241*cdf0e10cSrcweir { 242*cdf0e10cSrcweir *pLocales++ = CreateLocale( aIt->first ); 243*cdf0e10cSrcweir } 244*cdf0e10cSrcweir return aLocales; 245*cdf0e10cSrcweir } 246*cdf0e10cSrcweir 247*cdf0e10cSrcweir 248*cdf0e10cSrcweir sal_Bool SAL_CALL HyphenatorDispatcher::hasLocale(const Locale& rLocale) 249*cdf0e10cSrcweir throw(RuntimeException) 250*cdf0e10cSrcweir { 251*cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 252*cdf0e10cSrcweir HyphSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LocaleToLanguage( rLocale ) ) ); 253*cdf0e10cSrcweir return aIt != aSvcMap.end(); 254*cdf0e10cSrcweir } 255*cdf0e10cSrcweir 256*cdf0e10cSrcweir 257*cdf0e10cSrcweir Reference< XHyphenatedWord > SAL_CALL 258*cdf0e10cSrcweir HyphenatorDispatcher::hyphenate( 259*cdf0e10cSrcweir const OUString& rWord, const Locale& rLocale, sal_Int16 nMaxLeading, 260*cdf0e10cSrcweir const PropertyValues& rProperties ) 261*cdf0e10cSrcweir throw(IllegalArgumentException, RuntimeException) 262*cdf0e10cSrcweir { 263*cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 264*cdf0e10cSrcweir 265*cdf0e10cSrcweir Reference< XHyphenatedWord > xRes; 266*cdf0e10cSrcweir 267*cdf0e10cSrcweir sal_Int32 nWordLen = rWord.getLength(); 268*cdf0e10cSrcweir sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 269*cdf0e10cSrcweir if (nLanguage == LANGUAGE_NONE || !nWordLen || 270*cdf0e10cSrcweir nMaxLeading == 0 || nMaxLeading == nWordLen) 271*cdf0e10cSrcweir return xRes; 272*cdf0e10cSrcweir 273*cdf0e10cSrcweir // search for entry with that language 274*cdf0e10cSrcweir HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) ); 275*cdf0e10cSrcweir LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL; 276*cdf0e10cSrcweir 277*cdf0e10cSrcweir sal_Bool bWordModified = sal_False; 278*cdf0e10cSrcweir if (!pEntry || (nMaxLeading < 0 || nMaxLeading > nWordLen)) 279*cdf0e10cSrcweir { 280*cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS 281*cdf0e10cSrcweir throw IllegalArgumentException(); 282*cdf0e10cSrcweir #else 283*cdf0e10cSrcweir return NULL; 284*cdf0e10cSrcweir #endif 285*cdf0e10cSrcweir } 286*cdf0e10cSrcweir else 287*cdf0e10cSrcweir { 288*cdf0e10cSrcweir OUString aChkWord( rWord ); 289*cdf0e10cSrcweir 290*cdf0e10cSrcweir // replace typographical apostroph by ascii apostroph 291*cdf0e10cSrcweir String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() ); 292*cdf0e10cSrcweir DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" ); 293*cdf0e10cSrcweir if (aSingleQuote.Len()) 294*cdf0e10cSrcweir aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' ); 295*cdf0e10cSrcweir 296*cdf0e10cSrcweir bWordModified |= RemoveHyphens( aChkWord ); 297*cdf0e10cSrcweir if (IsIgnoreControlChars( rProperties, GetPropSet() )) 298*cdf0e10cSrcweir bWordModified |= RemoveControlChars( aChkWord ); 299*cdf0e10cSrcweir sal_Int16 nChkMaxLeading = (sal_Int16) GetPosInWordToCheck( rWord, nMaxLeading ); 300*cdf0e10cSrcweir 301*cdf0e10cSrcweir // check for results from (positive) dictionaries which have precedence! 302*cdf0e10cSrcweir Reference< XDictionaryEntry > xEntry; 303*cdf0e10cSrcweir 304*cdf0e10cSrcweir if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() )) 305*cdf0e10cSrcweir { 306*cdf0e10cSrcweir xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale, 307*cdf0e10cSrcweir sal_True, sal_False ); 308*cdf0e10cSrcweir } 309*cdf0e10cSrcweir 310*cdf0e10cSrcweir if (xEntry.is()) 311*cdf0e10cSrcweir { 312*cdf0e10cSrcweir //! because queryDictionaryEntry (in the end DictionaryNeo::getEntry) 313*cdf0e10cSrcweir //! does not distinguish betwee "XYZ" and "XYZ." in order to avoid 314*cdf0e10cSrcweir //! to require them as different entry we have to supply the 315*cdf0e10cSrcweir //! original word here as well so it can be used in th result 316*cdf0e10cSrcweir //! otherwise a strange effect may occur (see #i22591#) 317*cdf0e10cSrcweir xRes = buildHyphWord( rWord, xEntry, nLanguage, nChkMaxLeading ); 318*cdf0e10cSrcweir } 319*cdf0e10cSrcweir else 320*cdf0e10cSrcweir { 321*cdf0e10cSrcweir sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0; 322*cdf0e10cSrcweir DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen, 323*cdf0e10cSrcweir "lng : index out of range"); 324*cdf0e10cSrcweir 325*cdf0e10cSrcweir sal_Int32 i = 0; 326*cdf0e10cSrcweir Reference< XHyphenator > xHyph; 327*cdf0e10cSrcweir if (pEntry->aSvcRefs.getLength() > 0) 328*cdf0e10cSrcweir xHyph = pEntry->aSvcRefs[0]; 329*cdf0e10cSrcweir 330*cdf0e10cSrcweir // try already instantiated service 331*cdf0e10cSrcweir if (i <= pEntry->nLastTriedSvcIndex) 332*cdf0e10cSrcweir { 333*cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale )) 334*cdf0e10cSrcweir xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading, 335*cdf0e10cSrcweir rProperties ); 336*cdf0e10cSrcweir ++i; 337*cdf0e10cSrcweir } 338*cdf0e10cSrcweir else if (pEntry->nLastTriedSvcIndex < nLen - 1) 339*cdf0e10cSrcweir // instantiate services and try it 340*cdf0e10cSrcweir { 341*cdf0e10cSrcweir // const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray(); 342*cdf0e10cSrcweir Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray(); 343*cdf0e10cSrcweir 344*cdf0e10cSrcweir Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); 345*cdf0e10cSrcweir if (xMgr.is()) 346*cdf0e10cSrcweir { 347*cdf0e10cSrcweir // build service initialization argument 348*cdf0e10cSrcweir Sequence< Any > aArgs(2); 349*cdf0e10cSrcweir aArgs.getArray()[0] <<= GetPropSet(); 350*cdf0e10cSrcweir //! The dispatcher searches the dictionary-list 351*cdf0e10cSrcweir //! thus the service needs not to now about it 352*cdf0e10cSrcweir //aArgs.getArray()[1] <<= GetDicList(); 353*cdf0e10cSrcweir 354*cdf0e10cSrcweir // create specific service via it's implementation name 355*cdf0e10cSrcweir try 356*cdf0e10cSrcweir { 357*cdf0e10cSrcweir xHyph = Reference< XHyphenator >( 358*cdf0e10cSrcweir xMgr->createInstanceWithArguments( 359*cdf0e10cSrcweir pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY ); 360*cdf0e10cSrcweir } 361*cdf0e10cSrcweir catch (uno::Exception &) 362*cdf0e10cSrcweir { 363*cdf0e10cSrcweir DBG_ASSERT( 0, "createInstanceWithArguments failed" ); 364*cdf0e10cSrcweir } 365*cdf0e10cSrcweir pRef [i] = xHyph; 366*cdf0e10cSrcweir 367*cdf0e10cSrcweir Reference< XLinguServiceEventBroadcaster > 368*cdf0e10cSrcweir xBroadcaster( xHyph, UNO_QUERY ); 369*cdf0e10cSrcweir if (xBroadcaster.is()) 370*cdf0e10cSrcweir rMgr.AddLngSvcEvtBroadcaster( xBroadcaster ); 371*cdf0e10cSrcweir 372*cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale )) 373*cdf0e10cSrcweir xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading, 374*cdf0e10cSrcweir rProperties ); 375*cdf0e10cSrcweir 376*cdf0e10cSrcweir pEntry->nLastTriedSvcIndex = (sal_Int16) i; 377*cdf0e10cSrcweir ++i; 378*cdf0e10cSrcweir 379*cdf0e10cSrcweir // if language is not supported by the services 380*cdf0e10cSrcweir // remove it from the list. 381*cdf0e10cSrcweir if (xHyph.is() && !xHyph->hasLocale( rLocale )) 382*cdf0e10cSrcweir aSvcMap.erase( nLanguage ); 383*cdf0e10cSrcweir } 384*cdf0e10cSrcweir } 385*cdf0e10cSrcweir } // if (xEntry.is()) 386*cdf0e10cSrcweir } 387*cdf0e10cSrcweir 388*cdf0e10cSrcweir if (bWordModified && xRes.is()) 389*cdf0e10cSrcweir xRes = RebuildHyphensAndControlChars( rWord, xRes ); 390*cdf0e10cSrcweir 391*cdf0e10cSrcweir if (xRes.is() && xRes->getWord() != rWord) 392*cdf0e10cSrcweir { 393*cdf0e10cSrcweir xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(), 394*cdf0e10cSrcweir xRes->getHyphenatedWord(), 395*cdf0e10cSrcweir xRes->getHyphenPos() ); 396*cdf0e10cSrcweir } 397*cdf0e10cSrcweir 398*cdf0e10cSrcweir return xRes; 399*cdf0e10cSrcweir } 400*cdf0e10cSrcweir 401*cdf0e10cSrcweir 402*cdf0e10cSrcweir Reference< XHyphenatedWord > SAL_CALL 403*cdf0e10cSrcweir HyphenatorDispatcher::queryAlternativeSpelling( 404*cdf0e10cSrcweir const OUString& rWord, const Locale& rLocale, sal_Int16 nIndex, 405*cdf0e10cSrcweir const PropertyValues& rProperties ) 406*cdf0e10cSrcweir throw(IllegalArgumentException, RuntimeException) 407*cdf0e10cSrcweir { 408*cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 409*cdf0e10cSrcweir 410*cdf0e10cSrcweir Reference< XHyphenatedWord > xRes; 411*cdf0e10cSrcweir 412*cdf0e10cSrcweir sal_Int32 nWordLen = rWord.getLength(); 413*cdf0e10cSrcweir sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 414*cdf0e10cSrcweir if (nLanguage == LANGUAGE_NONE || !nWordLen) 415*cdf0e10cSrcweir return xRes; 416*cdf0e10cSrcweir 417*cdf0e10cSrcweir // search for entry with that language 418*cdf0e10cSrcweir HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) ); 419*cdf0e10cSrcweir LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL; 420*cdf0e10cSrcweir 421*cdf0e10cSrcweir sal_Bool bWordModified = sal_False; 422*cdf0e10cSrcweir if (!pEntry || !(0 <= nIndex && nIndex <= nWordLen - 2)) 423*cdf0e10cSrcweir { 424*cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS 425*cdf0e10cSrcweir throw IllegalArgumentException(); 426*cdf0e10cSrcweir #else 427*cdf0e10cSrcweir return NULL; 428*cdf0e10cSrcweir #endif 429*cdf0e10cSrcweir } 430*cdf0e10cSrcweir else 431*cdf0e10cSrcweir { 432*cdf0e10cSrcweir OUString aChkWord( rWord ); 433*cdf0e10cSrcweir 434*cdf0e10cSrcweir // replace typographical apostroph by ascii apostroph 435*cdf0e10cSrcweir String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() ); 436*cdf0e10cSrcweir DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" ); 437*cdf0e10cSrcweir if (aSingleQuote.Len()) 438*cdf0e10cSrcweir aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' ); 439*cdf0e10cSrcweir 440*cdf0e10cSrcweir bWordModified |= RemoveHyphens( aChkWord ); 441*cdf0e10cSrcweir if (IsIgnoreControlChars( rProperties, GetPropSet() )) 442*cdf0e10cSrcweir bWordModified |= RemoveControlChars( aChkWord ); 443*cdf0e10cSrcweir sal_Int16 nChkIndex = (sal_Int16) GetPosInWordToCheck( rWord, nIndex ); 444*cdf0e10cSrcweir 445*cdf0e10cSrcweir // check for results from (positive) dictionaries which have precedence! 446*cdf0e10cSrcweir Reference< XDictionaryEntry > xEntry; 447*cdf0e10cSrcweir 448*cdf0e10cSrcweir if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() )) 449*cdf0e10cSrcweir { 450*cdf0e10cSrcweir xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale, 451*cdf0e10cSrcweir sal_True, sal_False ); 452*cdf0e10cSrcweir } 453*cdf0e10cSrcweir 454*cdf0e10cSrcweir if (xEntry.is()) 455*cdf0e10cSrcweir { 456*cdf0e10cSrcweir //! alternative spellings not yet supported by dictionaries 457*cdf0e10cSrcweir } 458*cdf0e10cSrcweir else 459*cdf0e10cSrcweir { 460*cdf0e10cSrcweir sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0; 461*cdf0e10cSrcweir DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen, 462*cdf0e10cSrcweir "lng : index out of range"); 463*cdf0e10cSrcweir 464*cdf0e10cSrcweir sal_Int32 i = 0; 465*cdf0e10cSrcweir Reference< XHyphenator > xHyph; 466*cdf0e10cSrcweir if (pEntry->aSvcRefs.getLength() > 0) 467*cdf0e10cSrcweir xHyph = pEntry->aSvcRefs[0]; 468*cdf0e10cSrcweir 469*cdf0e10cSrcweir // try already instantiated service 470*cdf0e10cSrcweir if (i <= pEntry->nLastTriedSvcIndex) 471*cdf0e10cSrcweir { 472*cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale )) 473*cdf0e10cSrcweir xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale, 474*cdf0e10cSrcweir nChkIndex, rProperties ); 475*cdf0e10cSrcweir ++i; 476*cdf0e10cSrcweir } 477*cdf0e10cSrcweir else if (pEntry->nLastTriedSvcIndex < nLen - 1) 478*cdf0e10cSrcweir // instantiate services and try it 479*cdf0e10cSrcweir { 480*cdf0e10cSrcweir // const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray(); 481*cdf0e10cSrcweir Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray(); 482*cdf0e10cSrcweir 483*cdf0e10cSrcweir Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); 484*cdf0e10cSrcweir if (xMgr.is()) 485*cdf0e10cSrcweir { 486*cdf0e10cSrcweir // build service initialization argument 487*cdf0e10cSrcweir Sequence< Any > aArgs(2); 488*cdf0e10cSrcweir aArgs.getArray()[0] <<= GetPropSet(); 489*cdf0e10cSrcweir //! The dispatcher searches the dictionary-list 490*cdf0e10cSrcweir //! thus the service needs not to now about it 491*cdf0e10cSrcweir //aArgs.getArray()[1] <<= GetDicList(); 492*cdf0e10cSrcweir 493*cdf0e10cSrcweir // create specific service via it's implementation name 494*cdf0e10cSrcweir try 495*cdf0e10cSrcweir { 496*cdf0e10cSrcweir xHyph = Reference< XHyphenator >( 497*cdf0e10cSrcweir xMgr->createInstanceWithArguments( 498*cdf0e10cSrcweir pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY ); 499*cdf0e10cSrcweir } 500*cdf0e10cSrcweir catch (uno::Exception &) 501*cdf0e10cSrcweir { 502*cdf0e10cSrcweir DBG_ASSERT( 0, "createInstanceWithArguments failed" ); 503*cdf0e10cSrcweir } 504*cdf0e10cSrcweir pRef [i] = xHyph; 505*cdf0e10cSrcweir 506*cdf0e10cSrcweir Reference< XLinguServiceEventBroadcaster > 507*cdf0e10cSrcweir xBroadcaster( xHyph, UNO_QUERY ); 508*cdf0e10cSrcweir if (xBroadcaster.is()) 509*cdf0e10cSrcweir rMgr.AddLngSvcEvtBroadcaster( xBroadcaster ); 510*cdf0e10cSrcweir 511*cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale )) 512*cdf0e10cSrcweir xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale, 513*cdf0e10cSrcweir nChkIndex, rProperties ); 514*cdf0e10cSrcweir 515*cdf0e10cSrcweir pEntry->nLastTriedSvcIndex = (sal_Int16) i; 516*cdf0e10cSrcweir ++i; 517*cdf0e10cSrcweir 518*cdf0e10cSrcweir // if language is not supported by the services 519*cdf0e10cSrcweir // remove it from the list. 520*cdf0e10cSrcweir if (xHyph.is() && !xHyph->hasLocale( rLocale )) 521*cdf0e10cSrcweir aSvcMap.erase( nLanguage ); 522*cdf0e10cSrcweir } 523*cdf0e10cSrcweir } 524*cdf0e10cSrcweir } // if (xEntry.is()) 525*cdf0e10cSrcweir } 526*cdf0e10cSrcweir 527*cdf0e10cSrcweir if (bWordModified && xRes.is()) 528*cdf0e10cSrcweir xRes = RebuildHyphensAndControlChars( rWord, xRes ); 529*cdf0e10cSrcweir 530*cdf0e10cSrcweir if (xRes.is() && xRes->getWord() != rWord) 531*cdf0e10cSrcweir { 532*cdf0e10cSrcweir xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(), 533*cdf0e10cSrcweir xRes->getHyphenatedWord(), 534*cdf0e10cSrcweir xRes->getHyphenPos() ); 535*cdf0e10cSrcweir } 536*cdf0e10cSrcweir 537*cdf0e10cSrcweir return xRes; 538*cdf0e10cSrcweir } 539*cdf0e10cSrcweir 540*cdf0e10cSrcweir 541*cdf0e10cSrcweir Reference< XPossibleHyphens > SAL_CALL 542*cdf0e10cSrcweir HyphenatorDispatcher::createPossibleHyphens( 543*cdf0e10cSrcweir const OUString& rWord, const Locale& rLocale, 544*cdf0e10cSrcweir const PropertyValues& rProperties ) 545*cdf0e10cSrcweir throw(IllegalArgumentException, RuntimeException) 546*cdf0e10cSrcweir { 547*cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 548*cdf0e10cSrcweir 549*cdf0e10cSrcweir Reference< XPossibleHyphens > xRes; 550*cdf0e10cSrcweir 551*cdf0e10cSrcweir sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 552*cdf0e10cSrcweir if (nLanguage == LANGUAGE_NONE || !rWord.getLength()) 553*cdf0e10cSrcweir return xRes; 554*cdf0e10cSrcweir 555*cdf0e10cSrcweir // search for entry with that language 556*cdf0e10cSrcweir HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) ); 557*cdf0e10cSrcweir LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL; 558*cdf0e10cSrcweir 559*cdf0e10cSrcweir if (!pEntry) 560*cdf0e10cSrcweir { 561*cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS 562*cdf0e10cSrcweir throw IllegalArgumentException(); 563*cdf0e10cSrcweir #endif 564*cdf0e10cSrcweir } 565*cdf0e10cSrcweir else 566*cdf0e10cSrcweir { 567*cdf0e10cSrcweir OUString aChkWord( rWord ); 568*cdf0e10cSrcweir 569*cdf0e10cSrcweir // replace typographical apostroph by ascii apostroph 570*cdf0e10cSrcweir String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() ); 571*cdf0e10cSrcweir DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" ); 572*cdf0e10cSrcweir if (aSingleQuote.Len()) 573*cdf0e10cSrcweir aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' ); 574*cdf0e10cSrcweir 575*cdf0e10cSrcweir RemoveHyphens( aChkWord ); 576*cdf0e10cSrcweir if (IsIgnoreControlChars( rProperties, GetPropSet() )) 577*cdf0e10cSrcweir RemoveControlChars( aChkWord ); 578*cdf0e10cSrcweir 579*cdf0e10cSrcweir // check for results from (positive) dictionaries which have precedence! 580*cdf0e10cSrcweir Reference< XDictionaryEntry > xEntry; 581*cdf0e10cSrcweir 582*cdf0e10cSrcweir if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() )) 583*cdf0e10cSrcweir { 584*cdf0e10cSrcweir xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale, 585*cdf0e10cSrcweir sal_True, sal_False ); 586*cdf0e10cSrcweir } 587*cdf0e10cSrcweir 588*cdf0e10cSrcweir if (xEntry.is()) 589*cdf0e10cSrcweir { 590*cdf0e10cSrcweir xRes = buildPossHyphens( xEntry, nLanguage ); 591*cdf0e10cSrcweir } 592*cdf0e10cSrcweir else 593*cdf0e10cSrcweir { 594*cdf0e10cSrcweir sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0; 595*cdf0e10cSrcweir DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen, 596*cdf0e10cSrcweir "lng : index out of range"); 597*cdf0e10cSrcweir 598*cdf0e10cSrcweir sal_Int32 i = 0; 599*cdf0e10cSrcweir Reference< XHyphenator > xHyph; 600*cdf0e10cSrcweir if (pEntry->aSvcRefs.getLength() > 0) 601*cdf0e10cSrcweir xHyph = pEntry->aSvcRefs[0]; 602*cdf0e10cSrcweir 603*cdf0e10cSrcweir // try already instantiated service 604*cdf0e10cSrcweir if (i <= pEntry->nLastTriedSvcIndex) 605*cdf0e10cSrcweir { 606*cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale )) 607*cdf0e10cSrcweir xRes = xHyph->createPossibleHyphens( aChkWord, rLocale, 608*cdf0e10cSrcweir rProperties ); 609*cdf0e10cSrcweir ++i; 610*cdf0e10cSrcweir } 611*cdf0e10cSrcweir else if (pEntry->nLastTriedSvcIndex < nLen - 1) 612*cdf0e10cSrcweir // instantiate services and try it 613*cdf0e10cSrcweir { 614*cdf0e10cSrcweir // const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray(); 615*cdf0e10cSrcweir Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray(); 616*cdf0e10cSrcweir 617*cdf0e10cSrcweir Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); 618*cdf0e10cSrcweir if (xMgr.is()) 619*cdf0e10cSrcweir { 620*cdf0e10cSrcweir // build service initialization argument 621*cdf0e10cSrcweir Sequence< Any > aArgs(2); 622*cdf0e10cSrcweir aArgs.getArray()[0] <<= GetPropSet(); 623*cdf0e10cSrcweir //! The dispatcher searches the dictionary-list 624*cdf0e10cSrcweir //! thus the service needs not to now about it 625*cdf0e10cSrcweir //aArgs.getArray()[1] <<= GetDicList(); 626*cdf0e10cSrcweir 627*cdf0e10cSrcweir // create specific service via it's implementation name 628*cdf0e10cSrcweir try 629*cdf0e10cSrcweir { 630*cdf0e10cSrcweir xHyph = Reference< XHyphenator >( 631*cdf0e10cSrcweir xMgr->createInstanceWithArguments( 632*cdf0e10cSrcweir pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY ); 633*cdf0e10cSrcweir } 634*cdf0e10cSrcweir catch (uno::Exception &) 635*cdf0e10cSrcweir { 636*cdf0e10cSrcweir DBG_ASSERT( 0, "createWithArguments failed" ); 637*cdf0e10cSrcweir } 638*cdf0e10cSrcweir pRef [i] = xHyph; 639*cdf0e10cSrcweir 640*cdf0e10cSrcweir Reference< XLinguServiceEventBroadcaster > 641*cdf0e10cSrcweir xBroadcaster( xHyph, UNO_QUERY ); 642*cdf0e10cSrcweir if (xBroadcaster.is()) 643*cdf0e10cSrcweir rMgr.AddLngSvcEvtBroadcaster( xBroadcaster ); 644*cdf0e10cSrcweir 645*cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale )) 646*cdf0e10cSrcweir xRes = xHyph->createPossibleHyphens( aChkWord, rLocale, 647*cdf0e10cSrcweir rProperties ); 648*cdf0e10cSrcweir 649*cdf0e10cSrcweir pEntry->nLastTriedSvcIndex = (sal_Int16) i; 650*cdf0e10cSrcweir ++i; 651*cdf0e10cSrcweir 652*cdf0e10cSrcweir // if language is not supported by the services 653*cdf0e10cSrcweir // remove it from the list. 654*cdf0e10cSrcweir if (xHyph.is() && !xHyph->hasLocale( rLocale )) 655*cdf0e10cSrcweir aSvcMap.erase( nLanguage ); 656*cdf0e10cSrcweir } 657*cdf0e10cSrcweir } 658*cdf0e10cSrcweir } // if (xEntry.is()) 659*cdf0e10cSrcweir } 660*cdf0e10cSrcweir 661*cdf0e10cSrcweir if (xRes.is() && xRes->getWord() != rWord) 662*cdf0e10cSrcweir { 663*cdf0e10cSrcweir xRes = new PossibleHyphens( rWord, nLanguage, 664*cdf0e10cSrcweir xRes->getPossibleHyphens(), 665*cdf0e10cSrcweir xRes->getHyphenationPositions() ); 666*cdf0e10cSrcweir } 667*cdf0e10cSrcweir 668*cdf0e10cSrcweir return xRes; 669*cdf0e10cSrcweir } 670*cdf0e10cSrcweir 671*cdf0e10cSrcweir 672*cdf0e10cSrcweir void HyphenatorDispatcher::SetServiceList( const Locale &rLocale, 673*cdf0e10cSrcweir const Sequence< OUString > &rSvcImplNames ) 674*cdf0e10cSrcweir { 675*cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 676*cdf0e10cSrcweir 677*cdf0e10cSrcweir sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 678*cdf0e10cSrcweir 679*cdf0e10cSrcweir sal_Int32 nLen = rSvcImplNames.getLength(); 680*cdf0e10cSrcweir if (0 == nLen) 681*cdf0e10cSrcweir // remove entry 682*cdf0e10cSrcweir aSvcMap.erase( nLanguage ); 683*cdf0e10cSrcweir else 684*cdf0e10cSrcweir { 685*cdf0e10cSrcweir // modify/add entry 686*cdf0e10cSrcweir LangSvcEntries_Hyph *pEntry = aSvcMap[ nLanguage ].get(); 687*cdf0e10cSrcweir // only one hypenator can be in use for a language... 688*cdf0e10cSrcweir //const OUString &rSvcImplName = rSvcImplNames.getConstArray()[0]; 689*cdf0e10cSrcweir if (pEntry) 690*cdf0e10cSrcweir { 691*cdf0e10cSrcweir pEntry->Clear(); 692*cdf0e10cSrcweir pEntry->aSvcImplNames = rSvcImplNames; 693*cdf0e10cSrcweir pEntry->aSvcImplNames.realloc(1); 694*cdf0e10cSrcweir pEntry->aSvcRefs = Sequence< Reference < XHyphenator > > ( 1 ); 695*cdf0e10cSrcweir } 696*cdf0e10cSrcweir else 697*cdf0e10cSrcweir { 698*cdf0e10cSrcweir boost::shared_ptr< LangSvcEntries_Hyph > pTmpEntry( new LangSvcEntries_Hyph( rSvcImplNames[0] ) ); 699*cdf0e10cSrcweir pTmpEntry->aSvcRefs = Sequence< Reference < XHyphenator > >( 1 ); 700*cdf0e10cSrcweir aSvcMap[ nLanguage ] = pTmpEntry; 701*cdf0e10cSrcweir } 702*cdf0e10cSrcweir } 703*cdf0e10cSrcweir } 704*cdf0e10cSrcweir 705*cdf0e10cSrcweir 706*cdf0e10cSrcweir Sequence< OUString > 707*cdf0e10cSrcweir HyphenatorDispatcher::GetServiceList( const Locale &rLocale ) const 708*cdf0e10cSrcweir { 709*cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() ); 710*cdf0e10cSrcweir 711*cdf0e10cSrcweir Sequence< OUString > aRes; 712*cdf0e10cSrcweir 713*cdf0e10cSrcweir // search for entry with that language and use data from that 714*cdf0e10cSrcweir sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 715*cdf0e10cSrcweir HyphenatorDispatcher *pThis = (HyphenatorDispatcher *) this; 716*cdf0e10cSrcweir const HyphSvcByLangMap_t::iterator aIt( pThis->aSvcMap.find( nLanguage ) ); 717*cdf0e10cSrcweir const LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL; 718*cdf0e10cSrcweir if (pEntry) 719*cdf0e10cSrcweir { 720*cdf0e10cSrcweir aRes = pEntry->aSvcImplNames; 721*cdf0e10cSrcweir if (aRes.getLength() > 0) 722*cdf0e10cSrcweir aRes.realloc(1); 723*cdf0e10cSrcweir } 724*cdf0e10cSrcweir 725*cdf0e10cSrcweir return aRes; 726*cdf0e10cSrcweir } 727*cdf0e10cSrcweir 728*cdf0e10cSrcweir 729*cdf0e10cSrcweir LinguDispatcher::DspType HyphenatorDispatcher::GetDspType() const 730*cdf0e10cSrcweir { 731*cdf0e10cSrcweir return DSP_HYPH; 732*cdf0e10cSrcweir } 733*cdf0e10cSrcweir 734*cdf0e10cSrcweir 735*cdf0e10cSrcweir /////////////////////////////////////////////////////////////////////////// 736*cdf0e10cSrcweir 737