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 #if defined(WNT)
28 #include <tools/prewin.h>
29 #endif
30 
31 #if defined(WNT)
32 #include <Windows.h>
33 #endif
34 
35 #if defined(WNT)
36 #include <tools/postwin.h>
37 #endif
38 
39 
40 #include <osl/thread.h>
41 #include <osl/file.hxx>
42 #include <tools/debug.hxx>
43 #include <tools/urlobj.hxx>
44 #include <i18npool/mslangid.hxx>
45 #include <unotools/lingucfg.hxx>
46 #include <unotools/pathoptions.hxx>
47 #include <rtl/ustring.hxx>
48 #include <rtl/string.hxx>
49 #include <rtl/tencinfo.h>
50 #include <linguistic/misc.hxx>
51 
52 #include <set>
53 #include <vector>
54 #include <string.h>
55 
56 #include <lingutil.hxx>
57 #include <dictmgr.hxx>
58 
59 
60 
61 
62 using ::com::sun::star::lang::Locale;
63 using namespace ::com::sun::star;
64 
65 #if 0
66 //////////////////////////////////////////////////////////////////////
67 
68 String GetDirectoryPathFromFileURL( const String &rFileURL )
69 {
70     // get file URL
71     INetURLObject aURLObj;
72     aURLObj.SetSmartProtocol( INET_PROT_FILE );
73     aURLObj.SetSmartURL( rFileURL );
74     aURLObj.removeSegment();
75     DBG_ASSERT( !aURLObj.HasError(), "invalid URL" );
76     String aRes = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
77     return aRes;
78 }
79 #endif
80 
81 #if defined(WNT)
82 rtl::OString Win_GetShortPathName( const rtl::OUString &rLongPathName )
83 {
84     rtl::OString aRes;
85 
86     sal_Unicode aShortBuffer[1024] = {0};
87     sal_Int32   nShortBufSize = sizeof( aShortBuffer ) / sizeof( aShortBuffer[0] );
88 
89     // use the version of 'GetShortPathName' that can deal with Unicode...
90     sal_Int32 nShortLen = GetShortPathNameW(
91             reinterpret_cast<LPCWSTR>( rLongPathName.getStr() ),
92             reinterpret_cast<LPWSTR>( aShortBuffer ),
93             nShortBufSize );
94 
95     if (nShortLen < nShortBufSize) // conversion successful?
96         aRes = rtl::OString( OU2ENC( rtl::OUString( aShortBuffer, nShortLen ), osl_getThreadTextEncoding()) );
97     else
98         DBG_ERROR( "Win_GetShortPathName: buffer to short" );
99 
100     return aRes;
101 }
102 #endif //defined(WNT)
103 
104 //////////////////////////////////////////////////////////////////////
105 
106 // build list of old style diuctionaries (not as extensions) to use.
107 // User installed dictionaries (the ones residing in the user paths)
108 // will get precedence over system installed ones for the same language.
109 std::vector< SvtLinguConfigDictionaryEntry > GetOldStyleDics( const char *pDicType )
110 {
111     std::vector< SvtLinguConfigDictionaryEntry > aRes;
112 
113 	if (!pDicType)
114 		return aRes;
115 
116 	rtl::OUString aFormatName;
117 	String aDicExtension;
118 #ifdef SYSTEM_DICTS
119 	rtl::OUString aSystemDir;
120 	rtl::OUString aSystemPrefix;
121 	rtl::OUString aSystemSuffix;
122 #endif
123 	bool bSpell = false;
124 	bool bHyph  = false;
125 	bool bThes  = false;
126     if (strcmp( pDicType, "DICT" ) == 0)
127 	{
128 		aFormatName		= A2OU("DICT_SPELL");
129 		aDicExtension	= String::CreateFromAscii( ".dic" );
130 #ifdef SYSTEM_DICTS
131 		aSystemDir		= A2OU( DICT_SYSTEM_DIR );
132 		aSystemSuffix		= aDicExtension;
133 #endif
134 		bSpell = true;
135 	}
136     else if (strcmp( pDicType, "HYPH" ) == 0)
137 	{
138 		aFormatName		= A2OU("DICT_HYPH");
139 		aDicExtension	= String::CreateFromAscii( ".dic" );
140 #ifdef SYSTEM_DICTS
141 		aSystemDir		= A2OU( HYPH_SYSTEM_DIR );
142 		aSystemPrefix		= A2OU( "hyph_" );
143 		aSystemSuffix		= aDicExtension;
144 #endif
145 		bHyph = true;
146 	}
147     else if (strcmp( pDicType, "THES" ) == 0)
148 	{
149 		aFormatName		= A2OU("DICT_THES");
150 		aDicExtension	= String::CreateFromAscii( ".dat" );
151 #ifdef SYSTEM_DICTS
152 		aSystemDir		= A2OU( THES_SYSTEM_DIR );
153 		aSystemPrefix		= A2OU( "th_" );
154 		aSystemSuffix		= A2OU( "_v2.dat" );
155 #endif
156 		bThes = true;
157 	}
158 
159 
160 	if (aFormatName.getLength() == 0 || aDicExtension.Len() == 0)
161 		return aRes;
162 
163 	// set of languages to remember the language where it is already
164 	// decided to make use of the dictionary.
165 	std::set< LanguageType > aDicLangInUse;
166 
167 #ifdef SYSTEM_DICTS
168    osl::Directory aSystemDicts(aSystemDir);
169    if (aSystemDicts.open() == osl::FileBase::E_None)
170    {
171        osl::DirectoryItem aItem;
172        osl::FileStatus aFileStatus(FileStatusMask_FileURL);
173        while (aSystemDicts.getNextItem(aItem) == osl::FileBase::E_None)
174        {
175            aItem.getFileStatus(aFileStatus);
176            rtl::OUString sPath = aFileStatus.getFileURL();
177            if (sPath.lastIndexOf(aSystemSuffix) == sPath.getLength()-aSystemSuffix.getLength())
178            {
179                sal_Int32 nStartIndex = sPath.lastIndexOf(sal_Unicode('/')) + 1;
180                if (!sPath.match(aSystemPrefix, nStartIndex))
181                    continue;
182                rtl::OUString sChunk = sPath.copy(0, sPath.getLength() - aSystemSuffix.getLength());
183                sal_Int32 nIndex = nStartIndex + aSystemPrefix.getLength();
184                rtl::OUString sLang = sChunk.getToken( 0, '_', nIndex );
185                if (!sLang.getLength())
186                    continue;
187                rtl::OUString sRegion;
188                if (nIndex != -1)
189                    sRegion = sChunk.copy( nIndex, sChunk.getLength() - nIndex );
190 
191                // Thus we first get the language of the dictionary
192                LanguageType nLang = MsLangId::convertIsoNamesToLanguage(
193                   sLang, sRegion );
194 
195                if (aDicLangInUse.count( nLang ) == 0)
196                {
197                    // remember the new language in use
198                    aDicLangInUse.insert( nLang );
199 
200                    // add the dictionary to the resulting vector
201                    SvtLinguConfigDictionaryEntry aDicEntry;
202                    aDicEntry.aLocations.realloc(1);
203                    aDicEntry.aLocaleNames.realloc(1);
204                    rtl::OUString aLocaleName( MsLangId::convertLanguageToIsoString( nLang ) );
205                    aDicEntry.aLocations[0] = sPath;
206                    aDicEntry.aFormatName = aFormatName;
207                    aDicEntry.aLocaleNames[0] = aLocaleName;
208                    aRes.push_back( aDicEntry );
209                }
210            }
211        }
212     }
213 
214 #endif
215 
216     return aRes;
217 }
218 
219 
220 void MergeNewStyleDicsAndOldStyleDics(
221 	std::list< SvtLinguConfigDictionaryEntry > &rNewStyleDics,
222 	const std::vector< SvtLinguConfigDictionaryEntry > &rOldStyleDics )
223 {
224 	// get list of languages supported by new style dictionaries
225 	std::set< LanguageType > aNewStyleLanguages;
226 	std::list< SvtLinguConfigDictionaryEntry >::const_iterator aIt;
227 	for (aIt = rNewStyleDics.begin() ;  aIt != rNewStyleDics.end();  ++aIt)
228 	{
229 		const uno::Sequence< rtl::OUString > aLocaleNames( aIt->aLocaleNames );
230 		sal_Int32 nLocaleNames = aLocaleNames.getLength();
231 		for (sal_Int32 k = 0;  k < nLocaleNames; ++k)
232 		{
233 			LanguageType nLang = MsLangId::convertIsoStringToLanguage( aLocaleNames[k] );
234 			aNewStyleLanguages.insert( nLang );
235 		}
236 	}
237 
238 	// now check all old style dictionaries if they will add a not yet
239 	// added language. If so add them to the resulting vector
240 	std::vector< SvtLinguConfigDictionaryEntry >::const_iterator aIt2;
241 	for (aIt2 = rOldStyleDics.begin();  aIt2 != rOldStyleDics.end();  ++aIt2)
242 	{
243 		sal_Int32 nOldStyleDics = aIt2->aLocaleNames.getLength();
244 
245 		// old style dics should only have one language listed...
246 		DBG_ASSERT( nOldStyleDics, "old style dictionary with more then one language found!");
247 		if (nOldStyleDics > 0)
248 		{
249 			LanguageType nLang = MsLangId::convertIsoStringToLanguage( aIt2->aLocaleNames[0] );
250 
251             if (nLang == LANGUAGE_DONTKNOW || nLang == LANGUAGE_NONE)
252             {
253                 DBG_ERROR( "old style dictionary with invalid language found!" );
254                 continue;
255             }
256 
257 			// language not yet added?
258 			if (aNewStyleLanguages.count( nLang ) == 0)
259 				rNewStyleDics.push_back( *aIt2 );
260 		}
261 		else
262 		{
263 			DBG_ERROR( "old style dictionary with no language found!" );
264 		}
265 	}
266 }
267 
268 
269 rtl_TextEncoding getTextEncodingFromCharset(const sal_Char* pCharset)
270 {
271     // default result: used to indicate that we failed to get the proper encoding
272     rtl_TextEncoding eRet = RTL_TEXTENCODING_DONTKNOW;
273 
274     if (pCharset)
275     {
276         eRet = rtl_getTextEncodingFromMimeCharset(pCharset);
277         if (eRet == RTL_TEXTENCODING_DONTKNOW)
278             eRet = rtl_getTextEncodingFromUnixCharset(pCharset);
279         if (eRet == RTL_TEXTENCODING_DONTKNOW)
280         {
281             if (strcmp("ISCII-DEVANAGARI", pCharset) == 0)
282                 eRet = RTL_TEXTENCODING_ISCII_DEVANAGARI;
283         }
284     }
285     return eRet;
286 }
287 
288 //////////////////////////////////////////////////////////////////////
289 
290