1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_lingucomponent.hxx"
26 
27 #include <iostream>
28 
29 #include <tools/debug.hxx>
30 
31 #include <sal/config.h>
32 #include <cppuhelper/factory.hxx>
33 #include <cppuhelper/implementationentry.hxx>
34 #include <cppuhelper/implbase2.hxx>
35 #include <tools/string.hxx>
36 
37 #include <simpleguesser.hxx>
38 #include <guess.hxx>
39 
40 //#include <cppuhelper/queryinterface.hxx> // helper for queryInterface() impl
41 
42 //#include <com/sun/star/lang/XMultiServiceFactory.hpp>
43 #include <com/sun/star/registry/XRegistryKey.hpp>
44 #include <com/sun/star/lang/XServiceInfo.hpp>
45 #include <com/sun/star/linguistic2/XLanguageGuessing.hpp>
46 #include <unotools/pathoptions.hxx>
47 #include <unotools/localfilehelper.hxx>
48 #include <osl/thread.h>
49 
50 using namespace ::rtl;
51 using namespace ::osl;
52 using namespace ::cppu;
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::uno;
55 using namespace ::com::sun::star::lang;
56 using namespace ::com::sun::star::linguistic2;
57 
58 namespace css = ::com::sun::star;
59 
60 //==================================================================================================
61 
62 #define A2OU(x) ::rtl::OUString::createFromAscii( x )
63 
64 #define SERVICENAME     "com.sun.star.linguistic2.LanguageGuessing"
65 
66 #define IMPLNAME        "com.sun.star.lingu2.LanguageGuessing"
67 
getSupportedServiceNames_LangGuess_Impl()68 static Sequence< OUString > getSupportedServiceNames_LangGuess_Impl()
69 {
70     Sequence<OUString> names(1);
71     names[0] = A2OU( SERVICENAME );
72     return names;
73 }
74 
getImplementationName_LangGuess_Impl()75 static OUString getImplementationName_LangGuess_Impl()
76 {
77     return A2OU( IMPLNAME );
78 }
79 
GetLangGuessMutex()80 static osl::Mutex &  GetLangGuessMutex()
81 {
82     static osl::Mutex aMutex;
83     return aMutex;
84 }
85 
86 
87 class LangGuess_Impl :
88     public ::cppu::WeakImplHelper2<
89         XLanguageGuessing,
90         XServiceInfo >
91 {
92     SimpleGuesser   m_aGuesser;
93     bool            m_bInitialized;
94     css::uno::Reference< css::uno::XComponentContext >  m_xContext;
95 
96     LangGuess_Impl( const LangGuess_Impl & ); // not defined
97     LangGuess_Impl & operator =( const LangGuess_Impl & ); // not defined
98 
~LangGuess_Impl()99     virtual ~LangGuess_Impl() {}
100     void    EnsureInitialized();
101 
102 public:
103     explicit LangGuess_Impl(css::uno::Reference< css::uno::XComponentContext > const & rxContext);
104 
105     // XServiceInfo	implementation
106     virtual OUString SAL_CALL getImplementationName(  ) throw(RuntimeException);
107     virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw(RuntimeException);
108     virtual Sequence< OUString > SAL_CALL getSupportedServiceNames(  ) throw(RuntimeException);
109     static Sequence< OUString > SAL_CALL getSupportedServiceNames_Static(  );
110 
111     // XLanguageGuessing implementation
112     virtual ::com::sun::star::lang::Locale SAL_CALL guessPrimaryLanguage( const ::rtl::OUString& aText, ::sal_Int32 nStartPos, ::sal_Int32 nLen ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
113     virtual void SAL_CALL disableLanguages( const ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale >& aLanguages ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
114     virtual void SAL_CALL enableLanguages( const ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale >& aLanguages ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
115     virtual ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > SAL_CALL getAvailableLanguages(  ) throw (::com::sun::star::uno::RuntimeException);
116     virtual ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > SAL_CALL getEnabledLanguages(  ) throw (::com::sun::star::uno::RuntimeException);
117     virtual ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > SAL_CALL getDisabledLanguages(  ) throw (::com::sun::star::uno::RuntimeException);
118 
119     // implementation specific
120     void SetFingerPrintsDB( const rtl::OUString &fileName ) throw (RuntimeException);
121 
122     static const OUString & SAL_CALL getImplementationName_Static() throw();
123 
124 };
125 
126 //*************************************************************************
127 
LangGuess_Impl(css::uno::Reference<css::uno::XComponentContext> const & rxContext)128 LangGuess_Impl::LangGuess_Impl(css::uno::Reference< css::uno::XComponentContext > const & rxContext) :
129     m_bInitialized( false ),
130     m_xContext( rxContext )
131 {
132 }
133 
134 //*************************************************************************
135 
EnsureInitialized()136 void LangGuess_Impl::EnsureInitialized()
137 {
138     if (!m_bInitialized)
139     {
140         // set this to true at the very start to prevent loops because of
141         // implicitly called functions below
142         m_bInitialized = true;
143 
144         // set default fingerprint path to where those get installed
145         String aPhysPath;
146         String aURL( SvtPathOptions().GetFingerprintPath() );
147         utl::LocalFileHelper::ConvertURLToPhysicalName( aURL, aPhysPath );
148 #ifdef WNT
149             aPhysPath += '\\';
150 #else
151             aPhysPath += '/';
152 #endif
153 
154         SetFingerPrintsDB( aPhysPath );
155 
156         //
157         // disable currently not functional languages...
158         //
159         struct LangCountry
160         {
161             const char *pLang;
162             const char *pCountry;
163         };
164         LangCountry aDisable[] =
165         {
166             {"gv", ""}, {"sco", ""},                            // no lang-id available yet...
167 //            {"hy", ""}, {"drt", ""},                          // 0 bytes fingerprints...
168             {"zh", "CN"}, {"zh", "TW"}, {"ja", ""}, {"ko", ""}, // not yet correct functional...
169             {"ka", ""}, {"hi", ""}, {"mr", ""}, {"ne", ""},
170             {"sa", ""}, {"ta", ""}, {"th", ""},
171             {"qu", ""}, {"yi", ""}
172         };
173         sal_Int32 nNum = sizeof(aDisable) / sizeof(aDisable[0]);
174         Sequence< Locale > aDisableSeq( nNum );
175         Locale *pDisableSeq = aDisableSeq.getArray();
176         for (sal_Int32 i = 0;  i < nNum;  ++i)
177         {
178             Locale aLocale;
179             aLocale.Language = OUString::createFromAscii( aDisable[i].pLang );
180             aLocale.Country  = OUString::createFromAscii( aDisable[i].pCountry );
181             pDisableSeq[i] = aLocale;
182         }
183         disableLanguages( aDisableSeq );
184         DBG_ASSERT( nNum == getDisabledLanguages().getLength(), "size mismatch" );
185     }
186 }
187 
188 //*************************************************************************
189 
190 /* TL: currently not part of the API
191 Sequence< com::sun::star::lang::Locale > SAL_CALL LangGuess_Impl::guessLanguages(
192         const rtl::OUString   &rText,
193         sal_Int32       nStartPos,
194         sal_Int32       nLen )
195     throw (RuntimeException)
196 {
197     Sequence< com::sun::star::lang::Locale > aRes;
198 
199     OString o = OUStringToOString( rText, RTL_TEXTENCODING_UTF8 );
200     vector<Guess> gs = m_aGuesser.GuessLanguage(o.pData->buffer);
201 
202     aRes.realloc(gs.size());
203 
204     com::sun::star::lang::Locale *pRes = aRes.getArray();
205 
206 #ifdef DEBUG
207     std::cout << " We have " << gs.size() << " candidates" << std::endl;
208 #endif
209 
210     for(int i = 0; i < gs.size() ; i++ ){
211         com::sun::star::lang::Locale current_aRes;
212 
213         current_aRes.Language   = A2OU( gs[i].getLanguage().c_str() );
214         current_aRes.Country    = A2OU( gs[i].getCountry().c_str() );
215 
216         pRes[i] = current_aRes;
217     }
218 
219     return aRes;
220 }
221 */
222 //*************************************************************************
223 
guessPrimaryLanguage(const::rtl::OUString & rText,::sal_Int32 nStartPos,::sal_Int32 nLen)224 Locale SAL_CALL LangGuess_Impl::guessPrimaryLanguage(
225         const ::rtl::OUString& rText,
226         ::sal_Int32 nStartPos,
227         ::sal_Int32 nLen )
228     throw (lang::IllegalArgumentException, uno::RuntimeException)
229 {
230     osl::MutexGuard aGuard( GetLangGuessMutex() );
231 
232     EnsureInitialized();
233 
234 	lang::Locale aRes;
235 	if (nStartPos >=0 && nLen >= 0 && nStartPos + nLen <= rText.getLength())
236 	{
237 		OString o( OUStringToOString( rText.copy(nStartPos, nLen), RTL_TEXTENCODING_UTF8 ) );
238         Guess g = m_aGuesser.GuessPrimaryLanguage((char*)o.getStr());
239 		aRes.Language   = OUString::createFromAscii(g.GetLanguage().c_str());
240 		aRes.Country    = OUString::createFromAscii(g.GetCountry().c_str());
241 	}
242 	else
243 		throw lang::IllegalArgumentException();
244 
245 	return aRes;
246 }
247 
248 //*************************************************************************
249 #define DEFAULT_CONF_FILE_NAME "fpdb.conf"
250 
SetFingerPrintsDB(const rtl::OUString & filePath)251 void LangGuess_Impl::SetFingerPrintsDB(
252         const rtl::OUString &filePath )
253     throw (RuntimeException)
254 {
255 	//! text encoding for file name / path needs to be in the same encoding the OS uses
256     OString path = OUStringToOString( filePath, osl_getThreadTextEncoding() );
257     OString conf_file_name( DEFAULT_CONF_FILE_NAME );
258     OString conf_file_path(path);
259     conf_file_path += conf_file_name;
260 
261     //cout << "Conf file : " << conf_file_path.getStr() << " directory : " << path.getStr() << endl;
262 
263     m_aGuesser.SetDBPath((const char*)conf_file_path.getStr(), (const char*)path.getStr());
264 }
265 
266 //*************************************************************************
getAvailableLanguages()267 uno::Sequence< Locale > SAL_CALL LangGuess_Impl::getAvailableLanguages(  )
268         throw (uno::RuntimeException)
269 {
270     osl::MutexGuard aGuard( GetLangGuessMutex() );
271 
272     EnsureInitialized();
273 
274     Sequence< com::sun::star::lang::Locale > aRes;
275     vector<Guess> gs = m_aGuesser.GetAllManagedLanguages();
276     aRes.realloc(gs.size());
277 
278     com::sun::star::lang::Locale *pRes = aRes.getArray();
279 
280     for(size_t i = 0; i < gs.size() ; i++ ){
281         com::sun::star::lang::Locale current_aRes;
282         current_aRes.Language   = A2OU( gs[i].GetLanguage().c_str() );
283         current_aRes.Country    = A2OU( gs[i].GetCountry().c_str() );
284         pRes[i] = current_aRes;
285     }
286 
287     return aRes;
288 }
289 
290 //*************************************************************************
getEnabledLanguages()291 uno::Sequence< Locale > SAL_CALL LangGuess_Impl::getEnabledLanguages(  )
292         throw (uno::RuntimeException)
293 {
294     osl::MutexGuard aGuard( GetLangGuessMutex() );
295 
296     EnsureInitialized();
297 
298     Sequence< com::sun::star::lang::Locale > aRes;
299     vector<Guess> gs = m_aGuesser.GetAvailableLanguages();
300     aRes.realloc(gs.size());
301 
302     com::sun::star::lang::Locale *pRes = aRes.getArray();
303 
304     for(size_t i = 0; i < gs.size() ; i++ ){
305         com::sun::star::lang::Locale current_aRes;
306         current_aRes.Language   = A2OU( gs[i].GetLanguage().c_str() );
307         current_aRes.Country    = A2OU( gs[i].GetCountry().c_str() );
308         pRes[i] = current_aRes;
309     }
310 
311     return aRes;
312 }
313 
314 //*************************************************************************
getDisabledLanguages()315 uno::Sequence< Locale > SAL_CALL LangGuess_Impl::getDisabledLanguages(  )
316         throw (uno::RuntimeException)
317 {
318     osl::MutexGuard aGuard( GetLangGuessMutex() );
319 
320     EnsureInitialized();
321 
322     Sequence< com::sun::star::lang::Locale > aRes;
323     vector<Guess> gs = m_aGuesser.GetUnavailableLanguages();
324     aRes.realloc(gs.size());
325 
326     com::sun::star::lang::Locale *pRes = aRes.getArray();
327 
328     for(size_t i = 0; i < gs.size() ; i++ ){
329         com::sun::star::lang::Locale current_aRes;
330         current_aRes.Language   = A2OU( gs[i].GetLanguage().c_str() );
331         current_aRes.Country    = A2OU( gs[i].GetCountry().c_str() );
332         pRes[i] = current_aRes;
333     }
334 
335     return aRes;
336 }
337 
338 //*************************************************************************
disableLanguages(const uno::Sequence<Locale> & rLanguages)339 void SAL_CALL LangGuess_Impl::disableLanguages(
340         const uno::Sequence< Locale >& rLanguages )
341     throw (lang::IllegalArgumentException, uno::RuntimeException)
342 {
343     osl::MutexGuard aGuard( GetLangGuessMutex() );
344 
345     EnsureInitialized();
346 
347     sal_Int32 nLanguages = rLanguages.getLength();
348     const Locale *pLanguages = rLanguages.getConstArray();
349 
350     for (sal_Int32 i = 0;  i < nLanguages;  ++i)
351     {
352         string language;
353 
354         OString l = OUStringToOString( pLanguages[i].Language, RTL_TEXTENCODING_ASCII_US );
355         OString c = OUStringToOString( pLanguages[i].Country, RTL_TEXTENCODING_ASCII_US );
356 
357         language += l.getStr();
358         language += "-";
359         language += c.getStr();
360         m_aGuesser.DisableLanguage(language);
361     }
362 }
363 
364 //*************************************************************************
enableLanguages(const uno::Sequence<Locale> & rLanguages)365 void SAL_CALL LangGuess_Impl::enableLanguages(
366         const uno::Sequence< Locale >& rLanguages )
367     throw (lang::IllegalArgumentException, uno::RuntimeException)
368 {
369     osl::MutexGuard aGuard( GetLangGuessMutex() );
370 
371     EnsureInitialized();
372 
373     sal_Int32 nLanguages = rLanguages.getLength();
374     const Locale *pLanguages = rLanguages.getConstArray();
375 
376     for (sal_Int32 i = 0;  i < nLanguages;  ++i)
377     {
378         string language;
379 
380         OString l = OUStringToOString( pLanguages[i].Language, RTL_TEXTENCODING_ASCII_US );
381         OString c = OUStringToOString( pLanguages[i].Country, RTL_TEXTENCODING_ASCII_US );
382 
383         language += l.getStr();
384         language += "-";
385         language += c.getStr();
386         m_aGuesser.EnableLanguage(language);
387     }
388 }
389 
390 //*************************************************************************
getImplementationName()391 OUString SAL_CALL LangGuess_Impl::getImplementationName(  )
392 	throw(RuntimeException)
393 {
394     osl::MutexGuard aGuard( GetLangGuessMutex() );
395     return A2OU( IMPLNAME );
396 }
397 
398 //*************************************************************************
supportsService(const OUString & ServiceName)399 sal_Bool SAL_CALL LangGuess_Impl::supportsService( const OUString& ServiceName )
400 	throw(RuntimeException)
401 {
402     osl::MutexGuard aGuard( GetLangGuessMutex() );
403 	Sequence< OUString > aSNL = getSupportedServiceNames();
404 	const OUString * pArray = aSNL.getArray();
405 	for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
406 		if( pArray[i] == ServiceName )
407 			return sal_True;
408 	return sal_False;
409 }
410 
411 //*************************************************************************
getSupportedServiceNames()412 Sequence<OUString> SAL_CALL LangGuess_Impl::getSupportedServiceNames(  )
413 	throw(RuntimeException)
414 {
415     osl::MutexGuard aGuard( GetLangGuessMutex() );
416 	return getSupportedServiceNames_Static();
417 }
418 
419 //*************************************************************************
getSupportedServiceNames_Static()420 Sequence<OUString> SAL_CALL LangGuess_Impl::getSupportedServiceNames_Static(  )
421 {
422     OUString aName( A2OU( SERVICENAME ) );
423 	return Sequence< OUString >( &aName, 1 );
424 }
425 
426 //*************************************************************************
427 
428 
429 /**
430  * Function to create a new component instance; is needed by factory helper implementation.
431  * @param xMgr service manager to if the components needs other component instances
432  */
LangGuess_Impl_create(Reference<XComponentContext> const & xContext)433 Reference< XInterface > SAL_CALL LangGuess_Impl_create(
434     Reference< XComponentContext > const & xContext )
435     SAL_THROW( () )
436 {
437     return static_cast< ::cppu::OWeakObject * >( new LangGuess_Impl(xContext) );
438 }
439 
440 //##################################################################################################
441 //#### EXPORTED ### functions to allow for registration and creation of the UNO component
442 //##################################################################################################
443 
444 static struct ::cppu::ImplementationEntry s_component_entries [] =
445 {
446     {
447         LangGuess_Impl_create, getImplementationName_LangGuess_Impl,
448         getSupportedServiceNames_LangGuess_Impl,
449         ::cppu::createSingleComponentFactory,
450         0, 0
451     },
452     { 0, 0, 0, 0, 0, 0 }
453 };
454 
455 extern "C"
456 {
457 
component_getImplementationEnvironment(sal_Char const ** ppEnvTypeName,uno_Environment **)458 void SAL_CALL component_getImplementationEnvironment(
459     sal_Char const ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ )
460 {
461     *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
462 }
463 
component_getFactory(sal_Char const * implName,lang::XMultiServiceFactory * xMgr,registry::XRegistryKey * xRegistry)464 void * SAL_CALL component_getFactory(
465     sal_Char const * implName, lang::XMultiServiceFactory * xMgr,
466     registry::XRegistryKey * xRegistry )
467 {
468     return ::cppu::component_getFactoryHelper(
469         implName, xMgr, xRegistry, s_component_entries );
470 }
471 
472 }
473 
474