|
1 /******* BEGIN LICENSE BLOCK ******* |
|
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
|
3 * |
|
4 * The contents of this file are subject to the Mozilla Public License Version |
|
5 * 1.1 (the "License"); you may not use this file except in compliance with |
|
6 * the License. You may obtain a copy of the License at |
|
7 * http://www.mozilla.org/MPL/ |
|
8 * |
|
9 * Software distributed under the License is distributed on an "AS IS" basis, |
|
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
|
11 * for the specific language governing rights and limitations under the |
|
12 * License. |
|
13 * |
|
14 * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) |
|
15 * and László Németh (Hunspell). Portions created by the Initial Developers |
|
16 * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. |
|
17 * |
|
18 * Contributor(s): Kevin Hendricks (kevin.hendricks@sympatico.ca) |
|
19 * David Einstein (deinst@world.std.com) |
|
20 * Michiel van Leeuwen (mvl@exedo.nl) |
|
21 * Caolan McNamara (cmc@openoffice.org) |
|
22 * László Németh (nemethl@gyorsposta.hu) |
|
23 * Davide Prina |
|
24 * Giuseppe Modugno |
|
25 * Gianluca Turconi |
|
26 * Simon Brouwer |
|
27 * Noll Janos |
|
28 * Biro Arpad |
|
29 * Goldman Eleonora |
|
30 * Sarlos Tamas |
|
31 * Bencsath Boldizsar |
|
32 * Halacsy Peter |
|
33 * Dvornik Laszlo |
|
34 * Gefferth Andras |
|
35 * Nagy Viktor |
|
36 * Varga Daniel |
|
37 * Chris Halls |
|
38 * Rene Engelhard |
|
39 * Bram Moolenaar |
|
40 * Dafydd Jones |
|
41 * Harri Pitkanen |
|
42 * Andras Timar |
|
43 * Tor Lillqvist |
|
44 * Jesper Kristensen (mail@jesperkristensen.dk) |
|
45 * |
|
46 * Alternatively, the contents of this file may be used under the terms of |
|
47 * either the GNU General Public License Version 2 or later (the "GPL"), or |
|
48 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
|
49 * in which case the provisions of the GPL or the LGPL are applicable instead |
|
50 * of those above. If you wish to allow use of your version of this file only |
|
51 * under the terms of either the GPL or the LGPL, and not to allow others to |
|
52 * use your version of this file under the terms of the MPL, indicate your |
|
53 * decision by deleting the provisions above and replace them with the notice |
|
54 * and other provisions required by the GPL or the LGPL. If you do not delete |
|
55 * the provisions above, a recipient may use your version of this file under |
|
56 * the terms of any one of the MPL, the GPL or the LGPL. |
|
57 * |
|
58 ******* END LICENSE BLOCK *******/ |
|
59 |
|
60 #include "mozHunspell.h" |
|
61 #include "nsReadableUtils.h" |
|
62 #include "nsXPIDLString.h" |
|
63 #include "nsIObserverService.h" |
|
64 #include "nsISimpleEnumerator.h" |
|
65 #include "nsIDirectoryEnumerator.h" |
|
66 #include "nsIFile.h" |
|
67 #include "nsDirectoryServiceUtils.h" |
|
68 #include "nsDirectoryServiceDefs.h" |
|
69 #include "mozISpellI18NManager.h" |
|
70 #include "nsICharsetConverterManager.h" |
|
71 #include "nsUnicharUtilCIID.h" |
|
72 #include "nsUnicharUtils.h" |
|
73 #include "nsCRT.h" |
|
74 #include "mozInlineSpellChecker.h" |
|
75 #include "mozilla/Services.h" |
|
76 #include <stdlib.h> |
|
77 #include "nsIPrefService.h" |
|
78 #include "nsIPrefBranch.h" |
|
79 |
|
80 static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID); |
|
81 |
|
82 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozHunspell) |
|
83 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozHunspell) |
|
84 |
|
85 NS_INTERFACE_MAP_BEGIN(mozHunspell) |
|
86 NS_INTERFACE_MAP_ENTRY(mozISpellCheckingEngine) |
|
87 NS_INTERFACE_MAP_ENTRY(nsIObserver) |
|
88 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) |
|
89 NS_INTERFACE_MAP_ENTRY(nsIMemoryReporter) |
|
90 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozISpellCheckingEngine) |
|
91 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozHunspell) |
|
92 NS_INTERFACE_MAP_END |
|
93 |
|
94 NS_IMPL_CYCLE_COLLECTION(mozHunspell, |
|
95 mPersonalDictionary, |
|
96 mEncoder, |
|
97 mDecoder) |
|
98 |
|
99 template<> mozilla::Atomic<size_t> mozilla::CountingAllocatorBase<HunspellAllocator>::sAmount(0); |
|
100 |
|
101 mozHunspell::mozHunspell() |
|
102 : mHunspell(nullptr) |
|
103 { |
|
104 #ifdef DEBUG |
|
105 // There must be only one instance of this class: it reports memory based on |
|
106 // a single static count in HunspellAllocator. |
|
107 static bool hasRun = false; |
|
108 MOZ_ASSERT(!hasRun); |
|
109 hasRun = true; |
|
110 #endif |
|
111 } |
|
112 |
|
113 nsresult |
|
114 mozHunspell::Init() |
|
115 { |
|
116 LoadDictionaryList(); |
|
117 |
|
118 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
|
119 if (obs) { |
|
120 obs->AddObserver(this, "profile-do-change", true); |
|
121 obs->AddObserver(this, "profile-after-change", true); |
|
122 } |
|
123 |
|
124 mozilla::RegisterWeakMemoryReporter(this); |
|
125 |
|
126 return NS_OK; |
|
127 } |
|
128 |
|
129 mozHunspell::~mozHunspell() |
|
130 { |
|
131 mozilla::UnregisterWeakMemoryReporter(this); |
|
132 |
|
133 mPersonalDictionary = nullptr; |
|
134 delete mHunspell; |
|
135 } |
|
136 |
|
137 /* attribute wstring dictionary; */ |
|
138 NS_IMETHODIMP mozHunspell::GetDictionary(char16_t **aDictionary) |
|
139 { |
|
140 NS_ENSURE_ARG_POINTER(aDictionary); |
|
141 |
|
142 *aDictionary = ToNewUnicode(mDictionary); |
|
143 return *aDictionary ? NS_OK : NS_ERROR_OUT_OF_MEMORY; |
|
144 } |
|
145 |
|
146 /* set the Dictionary. |
|
147 * This also Loads the dictionary and initializes the converter using the dictionaries converter |
|
148 */ |
|
149 NS_IMETHODIMP mozHunspell::SetDictionary(const char16_t *aDictionary) |
|
150 { |
|
151 NS_ENSURE_ARG_POINTER(aDictionary); |
|
152 |
|
153 if (nsDependentString(aDictionary).IsEmpty()) { |
|
154 delete mHunspell; |
|
155 mHunspell = nullptr; |
|
156 mDictionary.AssignLiteral(""); |
|
157 mAffixFileName.AssignLiteral(""); |
|
158 mLanguage.AssignLiteral(""); |
|
159 mDecoder = nullptr; |
|
160 mEncoder = nullptr; |
|
161 |
|
162 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
|
163 if (obs) { |
|
164 obs->NotifyObservers(nullptr, |
|
165 SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, |
|
166 nullptr); |
|
167 } |
|
168 return NS_OK; |
|
169 } |
|
170 |
|
171 nsIFile* affFile = mDictionaries.GetWeak(nsDependentString(aDictionary)); |
|
172 if (!affFile) |
|
173 return NS_ERROR_FILE_NOT_FOUND; |
|
174 |
|
175 nsAutoCString dictFileName, affFileName; |
|
176 |
|
177 // XXX This isn't really good. nsIFile->NativePath isn't safe for all |
|
178 // character sets on Windows. |
|
179 // A better way would be to QI to nsIFile, and get a filehandle |
|
180 // from there. Only problem is that hunspell wants a path |
|
181 |
|
182 nsresult rv = affFile->GetNativePath(affFileName); |
|
183 NS_ENSURE_SUCCESS(rv, rv); |
|
184 |
|
185 if (mAffixFileName.Equals(affFileName.get())) |
|
186 return NS_OK; |
|
187 |
|
188 dictFileName = affFileName; |
|
189 int32_t dotPos = dictFileName.RFindChar('.'); |
|
190 if (dotPos == -1) |
|
191 return NS_ERROR_FAILURE; |
|
192 |
|
193 dictFileName.SetLength(dotPos); |
|
194 dictFileName.AppendLiteral(".dic"); |
|
195 |
|
196 // SetDictionary can be called multiple times, so we might have a |
|
197 // valid mHunspell instance which needs cleaned up. |
|
198 delete mHunspell; |
|
199 |
|
200 mDictionary = aDictionary; |
|
201 mAffixFileName = affFileName; |
|
202 |
|
203 mHunspell = new Hunspell(affFileName.get(), |
|
204 dictFileName.get()); |
|
205 if (!mHunspell) |
|
206 return NS_ERROR_OUT_OF_MEMORY; |
|
207 |
|
208 nsCOMPtr<nsICharsetConverterManager> ccm = |
|
209 do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); |
|
210 NS_ENSURE_SUCCESS(rv, rv); |
|
211 |
|
212 rv = ccm->GetUnicodeDecoder(mHunspell->get_dic_encoding(), |
|
213 getter_AddRefs(mDecoder)); |
|
214 NS_ENSURE_SUCCESS(rv, rv); |
|
215 |
|
216 rv = ccm->GetUnicodeEncoder(mHunspell->get_dic_encoding(), |
|
217 getter_AddRefs(mEncoder)); |
|
218 NS_ENSURE_SUCCESS(rv, rv); |
|
219 |
|
220 |
|
221 if (mEncoder) |
|
222 mEncoder->SetOutputErrorBehavior(mEncoder->kOnError_Signal, nullptr, '?'); |
|
223 |
|
224 int32_t pos = mDictionary.FindChar('-'); |
|
225 if (pos == -1) |
|
226 pos = mDictionary.FindChar('_'); |
|
227 |
|
228 if (pos == -1) |
|
229 mLanguage.Assign(mDictionary); |
|
230 else |
|
231 mLanguage = Substring(mDictionary, 0, pos); |
|
232 |
|
233 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
|
234 if (obs) { |
|
235 obs->NotifyObservers(nullptr, |
|
236 SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, |
|
237 nullptr); |
|
238 } |
|
239 |
|
240 return NS_OK; |
|
241 } |
|
242 |
|
243 /* readonly attribute wstring language; */ |
|
244 NS_IMETHODIMP mozHunspell::GetLanguage(char16_t **aLanguage) |
|
245 { |
|
246 NS_ENSURE_ARG_POINTER(aLanguage); |
|
247 |
|
248 if (mDictionary.IsEmpty()) |
|
249 return NS_ERROR_NOT_INITIALIZED; |
|
250 |
|
251 *aLanguage = ToNewUnicode(mLanguage); |
|
252 return *aLanguage ? NS_OK : NS_ERROR_OUT_OF_MEMORY; |
|
253 } |
|
254 |
|
255 /* readonly attribute boolean providesPersonalDictionary; */ |
|
256 NS_IMETHODIMP mozHunspell::GetProvidesPersonalDictionary(bool *aProvidesPersonalDictionary) |
|
257 { |
|
258 NS_ENSURE_ARG_POINTER(aProvidesPersonalDictionary); |
|
259 |
|
260 *aProvidesPersonalDictionary = false; |
|
261 return NS_OK; |
|
262 } |
|
263 |
|
264 /* readonly attribute boolean providesWordUtils; */ |
|
265 NS_IMETHODIMP mozHunspell::GetProvidesWordUtils(bool *aProvidesWordUtils) |
|
266 { |
|
267 NS_ENSURE_ARG_POINTER(aProvidesWordUtils); |
|
268 |
|
269 *aProvidesWordUtils = false; |
|
270 return NS_OK; |
|
271 } |
|
272 |
|
273 /* readonly attribute wstring name; */ |
|
274 NS_IMETHODIMP mozHunspell::GetName(char16_t * *aName) |
|
275 { |
|
276 return NS_ERROR_NOT_IMPLEMENTED; |
|
277 } |
|
278 |
|
279 /* readonly attribute wstring copyright; */ |
|
280 NS_IMETHODIMP mozHunspell::GetCopyright(char16_t * *aCopyright) |
|
281 { |
|
282 return NS_ERROR_NOT_IMPLEMENTED; |
|
283 } |
|
284 |
|
285 /* attribute mozIPersonalDictionary personalDictionary; */ |
|
286 NS_IMETHODIMP mozHunspell::GetPersonalDictionary(mozIPersonalDictionary * *aPersonalDictionary) |
|
287 { |
|
288 *aPersonalDictionary = mPersonalDictionary; |
|
289 NS_IF_ADDREF(*aPersonalDictionary); |
|
290 return NS_OK; |
|
291 } |
|
292 |
|
293 NS_IMETHODIMP mozHunspell::SetPersonalDictionary(mozIPersonalDictionary * aPersonalDictionary) |
|
294 { |
|
295 mPersonalDictionary = aPersonalDictionary; |
|
296 return NS_OK; |
|
297 } |
|
298 |
|
299 struct AppendNewStruct |
|
300 { |
|
301 char16_t **dics; |
|
302 uint32_t count; |
|
303 bool failed; |
|
304 }; |
|
305 |
|
306 static PLDHashOperator |
|
307 AppendNewString(const nsAString& aString, nsIFile* aFile, void* aClosure) |
|
308 { |
|
309 AppendNewStruct *ans = (AppendNewStruct*) aClosure; |
|
310 ans->dics[ans->count] = ToNewUnicode(aString); |
|
311 if (!ans->dics[ans->count]) { |
|
312 ans->failed = true; |
|
313 return PL_DHASH_STOP; |
|
314 } |
|
315 |
|
316 ++ans->count; |
|
317 return PL_DHASH_NEXT; |
|
318 } |
|
319 |
|
320 /* void GetDictionaryList ([array, size_is (count)] out wstring dictionaries, out uint32_t count); */ |
|
321 NS_IMETHODIMP mozHunspell::GetDictionaryList(char16_t ***aDictionaries, |
|
322 uint32_t *aCount) |
|
323 { |
|
324 if (!aDictionaries || !aCount) |
|
325 return NS_ERROR_NULL_POINTER; |
|
326 |
|
327 AppendNewStruct ans = { |
|
328 (char16_t**) NS_Alloc(sizeof(char16_t*) * mDictionaries.Count()), |
|
329 0, |
|
330 false |
|
331 }; |
|
332 |
|
333 // This pointer is used during enumeration |
|
334 mDictionaries.EnumerateRead(AppendNewString, &ans); |
|
335 |
|
336 if (ans.failed) { |
|
337 while (ans.count) { |
|
338 --ans.count; |
|
339 NS_Free(ans.dics[ans.count]); |
|
340 } |
|
341 NS_Free(ans.dics); |
|
342 return NS_ERROR_OUT_OF_MEMORY; |
|
343 } |
|
344 |
|
345 *aDictionaries = ans.dics; |
|
346 *aCount = ans.count; |
|
347 |
|
348 return NS_OK; |
|
349 } |
|
350 |
|
351 void |
|
352 mozHunspell::LoadDictionaryList() |
|
353 { |
|
354 mDictionaries.Clear(); |
|
355 |
|
356 nsresult rv; |
|
357 |
|
358 nsCOMPtr<nsIProperties> dirSvc = |
|
359 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); |
|
360 if (!dirSvc) |
|
361 return; |
|
362 |
|
363 // find built in dictionaries, or dictionaries specified in |
|
364 // spellchecker.dictionary_path in prefs |
|
365 nsCOMPtr<nsIFile> dictDir; |
|
366 |
|
367 // check preferences first |
|
368 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); |
|
369 if (prefs) { |
|
370 nsCString extDictPath; |
|
371 rv = prefs->GetCharPref("spellchecker.dictionary_path", getter_Copies(extDictPath)); |
|
372 if (NS_SUCCEEDED(rv)) { |
|
373 // set the spellchecker.dictionary_path |
|
374 rv = NS_NewNativeLocalFile(extDictPath, true, getter_AddRefs(dictDir)); |
|
375 } |
|
376 } |
|
377 if (!dictDir) { |
|
378 // spellcheck.dictionary_path not found, set internal path |
|
379 rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY, |
|
380 NS_GET_IID(nsIFile), getter_AddRefs(dictDir)); |
|
381 } |
|
382 if (dictDir) { |
|
383 LoadDictionariesFromDir(dictDir); |
|
384 } |
|
385 else { |
|
386 // try to load gredir/dictionaries |
|
387 nsCOMPtr<nsIFile> greDir; |
|
388 rv = dirSvc->Get(NS_GRE_DIR, |
|
389 NS_GET_IID(nsIFile), getter_AddRefs(greDir)); |
|
390 if (NS_SUCCEEDED(rv)) { |
|
391 greDir->AppendNative(NS_LITERAL_CSTRING("dictionaries")); |
|
392 LoadDictionariesFromDir(greDir); |
|
393 } |
|
394 |
|
395 // try to load appdir/dictionaries only if different than gredir |
|
396 nsCOMPtr<nsIFile> appDir; |
|
397 rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR, |
|
398 NS_GET_IID(nsIFile), getter_AddRefs(appDir)); |
|
399 bool equals; |
|
400 if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(appDir->Equals(greDir, &equals)) && !equals) { |
|
401 appDir->AppendNative(NS_LITERAL_CSTRING("dictionaries")); |
|
402 LoadDictionariesFromDir(appDir); |
|
403 } |
|
404 } |
|
405 |
|
406 // find dictionaries from extensions requiring restart |
|
407 nsCOMPtr<nsISimpleEnumerator> dictDirs; |
|
408 rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY_LIST, |
|
409 NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dictDirs)); |
|
410 if (NS_FAILED(rv)) |
|
411 return; |
|
412 |
|
413 bool hasMore; |
|
414 while (NS_SUCCEEDED(dictDirs->HasMoreElements(&hasMore)) && hasMore) { |
|
415 nsCOMPtr<nsISupports> elem; |
|
416 dictDirs->GetNext(getter_AddRefs(elem)); |
|
417 |
|
418 dictDir = do_QueryInterface(elem); |
|
419 if (dictDir) |
|
420 LoadDictionariesFromDir(dictDir); |
|
421 } |
|
422 |
|
423 // find dictionaries from restartless extensions |
|
424 for (int32_t i = 0; i < mDynamicDirectories.Count(); i++) { |
|
425 LoadDictionariesFromDir(mDynamicDirectories[i]); |
|
426 } |
|
427 |
|
428 // Now we have finished updating the list of dictionaries, update the current |
|
429 // dictionary and any editors which may use it. |
|
430 mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking(); |
|
431 |
|
432 // Check if the current dictionary is still available. |
|
433 // If not, try to replace it with another dictionary of the same language. |
|
434 if (!mDictionary.IsEmpty()) { |
|
435 rv = SetDictionary(mDictionary.get()); |
|
436 if (NS_SUCCEEDED(rv)) |
|
437 return; |
|
438 } |
|
439 |
|
440 // If the current dictionary has gone, and we don't have a good replacement, |
|
441 // set no current dictionary. |
|
442 if (!mDictionary.IsEmpty()) { |
|
443 SetDictionary(EmptyString().get()); |
|
444 } |
|
445 } |
|
446 |
|
447 NS_IMETHODIMP |
|
448 mozHunspell::LoadDictionariesFromDir(nsIFile* aDir) |
|
449 { |
|
450 nsresult rv; |
|
451 |
|
452 bool check = false; |
|
453 rv = aDir->Exists(&check); |
|
454 if (NS_FAILED(rv) || !check) |
|
455 return NS_ERROR_UNEXPECTED; |
|
456 |
|
457 rv = aDir->IsDirectory(&check); |
|
458 if (NS_FAILED(rv) || !check) |
|
459 return NS_ERROR_UNEXPECTED; |
|
460 |
|
461 nsCOMPtr<nsISimpleEnumerator> e; |
|
462 rv = aDir->GetDirectoryEntries(getter_AddRefs(e)); |
|
463 if (NS_FAILED(rv)) |
|
464 return NS_ERROR_UNEXPECTED; |
|
465 |
|
466 nsCOMPtr<nsIDirectoryEnumerator> files(do_QueryInterface(e)); |
|
467 if (!files) |
|
468 return NS_ERROR_UNEXPECTED; |
|
469 |
|
470 nsCOMPtr<nsIFile> file; |
|
471 while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file))) && file) { |
|
472 nsAutoString leafName; |
|
473 file->GetLeafName(leafName); |
|
474 if (!StringEndsWith(leafName, NS_LITERAL_STRING(".dic"))) |
|
475 continue; |
|
476 |
|
477 nsAutoString dict(leafName); |
|
478 dict.SetLength(dict.Length() - 4); // magic length of ".dic" |
|
479 |
|
480 // check for the presence of the .aff file |
|
481 leafName = dict; |
|
482 leafName.AppendLiteral(".aff"); |
|
483 file->SetLeafName(leafName); |
|
484 rv = file->Exists(&check); |
|
485 if (NS_FAILED(rv) || !check) |
|
486 continue; |
|
487 |
|
488 #ifdef DEBUG_bsmedberg |
|
489 printf("Adding dictionary: %s\n", NS_ConvertUTF16toUTF8(dict).get()); |
|
490 #endif |
|
491 |
|
492 mDictionaries.Put(dict, file); |
|
493 } |
|
494 |
|
495 return NS_OK; |
|
496 } |
|
497 |
|
498 nsresult mozHunspell::ConvertCharset(const char16_t* aStr, char ** aDst) |
|
499 { |
|
500 NS_ENSURE_ARG_POINTER(aDst); |
|
501 NS_ENSURE_TRUE(mEncoder, NS_ERROR_NULL_POINTER); |
|
502 |
|
503 int32_t outLength; |
|
504 int32_t inLength = NS_strlen(aStr); |
|
505 nsresult rv = mEncoder->GetMaxLength(aStr, inLength, &outLength); |
|
506 NS_ENSURE_SUCCESS(rv, rv); |
|
507 |
|
508 *aDst = (char *) nsMemory::Alloc(sizeof(char) * (outLength+1)); |
|
509 NS_ENSURE_TRUE(*aDst, NS_ERROR_OUT_OF_MEMORY); |
|
510 |
|
511 rv = mEncoder->Convert(aStr, &inLength, *aDst, &outLength); |
|
512 if (NS_SUCCEEDED(rv)) |
|
513 (*aDst)[outLength] = '\0'; |
|
514 |
|
515 return rv; |
|
516 } |
|
517 |
|
518 /* boolean Check (in wstring word); */ |
|
519 NS_IMETHODIMP mozHunspell::Check(const char16_t *aWord, bool *aResult) |
|
520 { |
|
521 NS_ENSURE_ARG_POINTER(aWord); |
|
522 NS_ENSURE_ARG_POINTER(aResult); |
|
523 NS_ENSURE_TRUE(mHunspell, NS_ERROR_FAILURE); |
|
524 |
|
525 nsXPIDLCString charsetWord; |
|
526 nsresult rv = ConvertCharset(aWord, getter_Copies(charsetWord)); |
|
527 NS_ENSURE_SUCCESS(rv, rv); |
|
528 |
|
529 *aResult = !!mHunspell->spell(charsetWord); |
|
530 |
|
531 |
|
532 if (!*aResult && mPersonalDictionary) |
|
533 rv = mPersonalDictionary->Check(aWord, mLanguage.get(), aResult); |
|
534 |
|
535 return rv; |
|
536 } |
|
537 |
|
538 /* void Suggest (in wstring word, [array, size_is (count)] out wstring suggestions, out uint32_t count); */ |
|
539 NS_IMETHODIMP mozHunspell::Suggest(const char16_t *aWord, char16_t ***aSuggestions, uint32_t *aSuggestionCount) |
|
540 { |
|
541 NS_ENSURE_ARG_POINTER(aSuggestions); |
|
542 NS_ENSURE_ARG_POINTER(aSuggestionCount); |
|
543 NS_ENSURE_TRUE(mHunspell, NS_ERROR_FAILURE); |
|
544 |
|
545 nsresult rv; |
|
546 *aSuggestionCount = 0; |
|
547 |
|
548 nsXPIDLCString charsetWord; |
|
549 rv = ConvertCharset(aWord, getter_Copies(charsetWord)); |
|
550 NS_ENSURE_SUCCESS(rv, rv); |
|
551 |
|
552 char ** wlst; |
|
553 *aSuggestionCount = mHunspell->suggest(&wlst, charsetWord); |
|
554 |
|
555 if (*aSuggestionCount) { |
|
556 *aSuggestions = (char16_t **)nsMemory::Alloc(*aSuggestionCount * sizeof(char16_t *)); |
|
557 if (*aSuggestions) { |
|
558 uint32_t index = 0; |
|
559 for (index = 0; index < *aSuggestionCount && NS_SUCCEEDED(rv); ++index) { |
|
560 // Convert the suggestion to utf16 |
|
561 int32_t inLength = strlen(wlst[index]); |
|
562 int32_t outLength; |
|
563 rv = mDecoder->GetMaxLength(wlst[index], inLength, &outLength); |
|
564 if (NS_SUCCEEDED(rv)) |
|
565 { |
|
566 (*aSuggestions)[index] = (char16_t *) nsMemory::Alloc(sizeof(char16_t) * (outLength+1)); |
|
567 if ((*aSuggestions)[index]) |
|
568 { |
|
569 rv = mDecoder->Convert(wlst[index], &inLength, (*aSuggestions)[index], &outLength); |
|
570 if (NS_SUCCEEDED(rv)) |
|
571 (*aSuggestions)[index][outLength] = 0; |
|
572 } |
|
573 else |
|
574 rv = NS_ERROR_OUT_OF_MEMORY; |
|
575 } |
|
576 } |
|
577 |
|
578 if (NS_FAILED(rv)) |
|
579 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(index, *aSuggestions); // free the char16_t strings up to the point at which the error occurred |
|
580 } |
|
581 else // if (*aSuggestions) |
|
582 rv = NS_ERROR_OUT_OF_MEMORY; |
|
583 } |
|
584 |
|
585 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(*aSuggestionCount, wlst); |
|
586 return rv; |
|
587 } |
|
588 |
|
589 NS_IMETHODIMP |
|
590 mozHunspell::Observe(nsISupports* aSubj, const char *aTopic, |
|
591 const char16_t *aData) |
|
592 { |
|
593 NS_ASSERTION(!strcmp(aTopic, "profile-do-change") |
|
594 || !strcmp(aTopic, "profile-after-change"), |
|
595 "Unexpected observer topic"); |
|
596 |
|
597 LoadDictionaryList(); |
|
598 |
|
599 return NS_OK; |
|
600 } |
|
601 |
|
602 /* void addDirectory(in nsIFile dir); */ |
|
603 NS_IMETHODIMP mozHunspell::AddDirectory(nsIFile *aDir) |
|
604 { |
|
605 mDynamicDirectories.AppendObject(aDir); |
|
606 LoadDictionaryList(); |
|
607 return NS_OK; |
|
608 } |
|
609 |
|
610 /* void removeDirectory(in nsIFile dir); */ |
|
611 NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir) |
|
612 { |
|
613 mDynamicDirectories.RemoveObject(aDir); |
|
614 LoadDictionaryList(); |
|
615 return NS_OK; |
|
616 } |