1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License
6
* as published by the Free Software Foundation; either version 2
7
* of the License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
* Fragments of this code are taken from Mozilla Spellchecker Component:
20
* The Initial Developer of the Original Code of Mozilla Spellchecker Component is
22
* Portions created by the Initial Developer are Copyright (C) 2001
23
* the Initial Developer. All Rights Reserved.
24
* Adapted for use of Voikko by Andris Pavenis <andris.pavenis@iki.fi>
26
* Contributor(s): David Einstein <Deinst@world.std.com>
27
* Kevin Hendricks <kevin.hendricks@sympatico.ca>
28
* Michiel van Leeuwen <mvl@exedo.nl>
29
* Harri Pitkänen <hatapitk@iki.fi>
31
* This spellchecker is based on the MySpell spellchecker made for Open Office
32
* by Kevin Hendricks. Although the algorithms and code, have changed
33
* slightly, the architecture is still the same. The Mozilla implementation
34
* is designed to be compatible with the Open Office dictionaries.
35
* Please do not make changes to the affix or dictionary file formats
36
* without attempting to coordinate with Kevin. For more information
37
* on the original MySpell see
38
* http://whiteboard.openoffice.org/source/browse/whiteboard/lingucomponent/source/spellcheck/myspell/
40
* A special thanks and credit goes to Geoff Kuenning
41
* the creator of ispell. MySpell's affix algorithms were
42
* based on those of ispell which should be noted is
43
* copyright Geoff Kuenning et.al. and now available
44
* under a BSD style license. For more information on ispell
45
* and affix compression in general, please see:
46
* http://www.cs.ucla.edu/ficus-members/geoff/ispell.html
47
* (the home page for ispell)
49
* ***** END LICENSE BLOCK ***** */
51
#include "mozVoikkoSpell.hxx"
52
#include "mozVoikkoUtils.hxx"
53
#include <nsISimpleEnumerator.h>
54
#include <nsServiceManagerUtils.h>
55
#include <nsICategoryManager.h>
56
#include <mozISpellI18NManager.h>
57
#include <nsICharsetConverterManager.h>
58
#include <nsISupportsPrimitives.h>
59
#include <nsUnicharUtilCIID.h>
60
#include <nsUnicharUtils.h>
61
#include <nsStringAPI.h>
62
#include <nsEmbedString.h>
63
#include <nsCRTGlue.h>
67
#define MOZVOIKKO_LANGUAGE_STRING "fi-FI"
69
const PRInt32 kFirstDirSize=8;
70
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
71
static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID);
73
NS_IMPL_ISUPPORTS1(mozVoikkoSpell, mozISpellCheckingEngine)
75
mozVoikkoSpell::mozVoikkoSpell()
80
mozVoikkoSpell::~mozVoikkoSpell()
82
mPersonalDictionary = nsnull;
86
/* attribute wstring dictionary; */
87
NS_IMETHODIMP mozVoikkoSpell::GetDictionary(PRUnichar **aDictionary)
89
NS_ENSURE_ARG_POINTER(aDictionary);
91
*aDictionary = ToNewUnicode(mDictionary);
92
return *aDictionary ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
95
/* set the Dictionary.
96
* This also Loads the dictionary and initializes the converter using the dictionaries converter
98
NS_IMETHODIMP mozVoikkoSpell::SetDictionary(const PRUnichar *aDictionary)
100
NS_ENSURE_ARG_POINTER(aDictionary);
102
nsString newDict(aDictionary);
105
if (!newDict.Equals(NS_LITERAL_STRING(MOZVOIKKO_LANGUAGE_STRING)))
107
logMessage("mozVoikko: dictionary '%s' is not supported",
108
NS_ConvertUTF16toUTF8(newDict).get());
109
return NS_ERROR_FAILURE;
112
if (!mDictionary.Equals(newDict))
114
mDictionary = aDictionary;
115
// FIXME: So we need that?.
118
voikkoSpell = new MozVoikko();
120
return NS_ERROR_FAILURE;
122
nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(kCharsetConverterManagerCID, &rv);
123
NS_ENSURE_SUCCESS(rv, rv);
125
rv = ccm->GetUnicodeDecoder(voikkoSpell->get_dic_encoding(), getter_AddRefs(mDecoder));
126
NS_ENSURE_SUCCESS(rv, rv);
127
rv = ccm->GetUnicodeEncoder(voikkoSpell->get_dic_encoding(), getter_AddRefs(mEncoder));
128
if (mEncoder && NS_SUCCEEDED(rv))
130
mEncoder->SetOutputErrorBehavior(mEncoder->kOnError_Signal, nsnull, '?');
133
NS_ENSURE_SUCCESS(rv, rv);
134
mLanguage.Assign(newDict);
144
/* readonly attribute wstring language; */
145
NS_IMETHODIMP mozVoikkoSpell::GetLanguage(PRUnichar **aLanguage)
147
NS_ENSURE_ARG_POINTER(aLanguage);
149
*aLanguage = ToNewUnicode(mLanguage);
150
return *aLanguage ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
153
/* readonly attribute boolean providesPersonalDictionary; */
154
NS_IMETHODIMP mozVoikkoSpell::GetProvidesPersonalDictionary(PRBool *aProvidesPersonalDictionary)
156
NS_ENSURE_ARG_POINTER(aProvidesPersonalDictionary);
158
*aProvidesPersonalDictionary = PR_FALSE;
162
/* readonly attribute boolean providesWordUtils; */
163
NS_IMETHODIMP mozVoikkoSpell::GetProvidesWordUtils(PRBool *aProvidesWordUtils)
165
NS_ENSURE_ARG_POINTER(aProvidesWordUtils);
167
*aProvidesWordUtils = PR_FALSE;
171
/* readonly attribute wstring name; */
172
NS_IMETHODIMP mozVoikkoSpell::GetName(PRUnichar * *aName)
174
return NS_ERROR_NOT_IMPLEMENTED;
177
/* readonly attribute wstring copyright; */
178
NS_IMETHODIMP mozVoikkoSpell::GetCopyright(PRUnichar * *aCopyright)
180
return NS_ERROR_NOT_IMPLEMENTED;
183
/* attribute mozIPersonalDictionary personalDictionary; */
184
NS_IMETHODIMP mozVoikkoSpell::GetPersonalDictionary(mozIPersonalDictionary * *aPersonalDictionary)
186
*aPersonalDictionary = mPersonalDictionary;
187
NS_IF_ADDREF(*aPersonalDictionary);
191
NS_IMETHODIMP mozVoikkoSpell::SetPersonalDictionary(mozIPersonalDictionary * aPersonalDictionary)
193
mPersonalDictionary = aPersonalDictionary;
197
/* void GetDictionaryList ([array, size_is (count)] out wstring dictionaries, out PRUint32 count); */
198
NS_IMETHODIMP mozVoikkoSpell::GetDictionaryList(PRUnichar ***aDictionaries, PRUint32 *aCount)
200
if (!aDictionaries || !aCount)
201
return NS_ERROR_NULL_POINTER;
206
PRUnichar **tmpPtr = (PRUnichar **) NS_Alloc(sizeof(PRUnichar *));
208
return NS_ERROR_OUT_OF_MEMORY;
212
MozVoikko voikkoSpell;
215
nsAutoString voikkoDictName(NS_LITERAL_STRING(MOZVOIKKO_LANGUAGE_STRING).get());
216
tmpPtr[0] = ToNewUnicode(voikkoDictName);
218
*aDictionaries = tmpPtr;
227
nsresult mozVoikkoSpell::ConvertCharset(const PRUnichar* aStr, char ** aDst)
229
NS_ENSURE_ARG_POINTER(aDst);
230
NS_ENSURE_TRUE(mEncoder, NS_ERROR_NULL_POINTER);
233
PRInt32 inLength = NS_strlen(aStr);
234
nsresult rv = mEncoder->GetMaxLength(aStr, inLength, &outLength);
235
NS_ENSURE_SUCCESS(rv, rv);
237
*aDst = (char *) NS_Alloc(sizeof(char) * (outLength+1));
238
NS_ENSURE_TRUE(*aDst, NS_ERROR_OUT_OF_MEMORY);
240
rv = mEncoder->Convert(aStr, &inLength, *aDst, &outLength);
241
if (NS_SUCCEEDED(rv))
242
(*aDst)[outLength] = '\0';
247
/* boolean Check (in wstring word); */
248
NS_IMETHODIMP mozVoikkoSpell::Check(const PRUnichar *aWord, PRBool *aResult)
250
NS_ENSURE_ARG_POINTER(aWord);
251
NS_ENSURE_ARG_POINTER(aResult);
252
NS_ENSURE_TRUE(voikkoSpell, NS_ERROR_FAILURE);
255
nsresult rv = ConvertCharset(aWord, &charsetWord);
256
NS_ENSURE_SUCCESS(rv, rv);
258
*aResult = voikkoSpell->spell(charsetWord);
260
NS_Free(charsetWord);
262
if (!*aResult && mPersonalDictionary)
263
rv = mPersonalDictionary->Check(aWord, mLanguage.get(), aResult);
268
/* void Suggest (in wstring word, [array, size_is (count)] out wstring suggestions, out PRUint32 count); */
269
NS_IMETHODIMP mozVoikkoSpell::Suggest(const PRUnichar *aWord, PRUnichar ***aSuggestions, PRUint32 *aSuggestionCount)
271
NS_ENSURE_ARG_POINTER(aSuggestions);
272
NS_ENSURE_ARG_POINTER(aSuggestionCount);
273
NS_ENSURE_TRUE(voikkoSpell, NS_ERROR_FAILURE);
276
*aSuggestionCount = 0;
279
rv = ConvertCharset(aWord, &charsetWord);
280
NS_ENSURE_SUCCESS(rv, rv);
283
*aSuggestionCount = voikkoSpell->suggest(&wlst, charsetWord);
284
NS_Free(charsetWord);
286
// This code is copy/pasted from mySpell (with format changes). Maybe
287
// it can be optimized.
288
if (*aSuggestionCount)
290
*aSuggestions = (PRUnichar **) NS_Alloc(*aSuggestionCount * sizeof(PRUnichar *));
294
for (index = 0; index < *aSuggestionCount && NS_SUCCEEDED(rv); ++index)
296
// Convert the suggestion to utf16
297
PRInt32 inLength = strlen(wlst[index]);
299
rv = mDecoder->GetMaxLength(wlst[index], inLength, &outLength);
300
if (NS_SUCCEEDED(rv))
302
(*aSuggestions)[index] = (PRUnichar *) NS_Alloc(sizeof(PRUnichar) * (outLength+1));
303
if ((*aSuggestions)[index])
305
rv = mDecoder->Convert(wlst[index], &inLength, (*aSuggestions)[index], &outLength);
306
if (NS_SUCCEEDED(rv))
307
(*aSuggestions)[index][outLength] = 0;
310
rv = NS_ERROR_OUT_OF_MEMORY;
315
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(index, *aSuggestions); // free the PRUnichar strings up to the point at which the error occurred
317
else // if (*aSuggestions)
318
rv = NS_ERROR_OUT_OF_MEMORY;
321
voikkoSpell->freeSuggestions(wlst);