extensions/spellcheck/hunspell/src/mozHunspell.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial