Back to index

lightning-sunbird  0.9+nobinonly
mozPersonalDictionary.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Spellchecker Component.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * David Einstein.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s): David Einstein <Deinst@world.std.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "mozPersonalDictionary.h"
00039 #include "nsIUnicharInputStream.h"
00040 #include "nsReadableUtils.h"
00041 #include "nsIFile.h"
00042 #include "nsAppDirectoryServiceDefs.h"
00043 #include "nsICharsetConverterManager.h"
00044 #include "nsICharsetAlias.h"
00045 #include "nsIObserverService.h"
00046 #include "nsIPrefService.h"
00047 #include "nsIPrefBranch.h"
00048 #include "nsIPrefBranch2.h"
00049 #include "nsIWeakReference.h"
00050 #include "nsCRT.h"
00051 #include "nsNetUtil.h"
00052 #include "nsStringEnumerator.h"
00053 
00054 #define MOZ_PERSONAL_DICT_NAME "persdict.dat"
00055 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
00056 
00057 const int kMaxWordLen=256;
00058 
00071 NS_IMPL_ISUPPORTS3(mozPersonalDictionary, mozIPersonalDictionary, nsIObserver, nsISupportsWeakReference)
00072 
00073 mozPersonalDictionary::mozPersonalDictionary()
00074  : mDirty(PR_FALSE)
00075 {
00076 }
00077 
00078 mozPersonalDictionary::~mozPersonalDictionary()
00079 {
00080 }
00081 
00082 nsresult mozPersonalDictionary::Init()
00083 {
00084   if (!mDictionaryTable.Init() || !mIgnoreTable.Init())
00085     return NS_ERROR_OUT_OF_MEMORY;
00086 
00087   nsresult rv;
00088   nsCOMPtr<nsIObserverService> svc = 
00089            do_GetService("@mozilla.org/observer-service;1", &rv);
00090    
00091   if (NS_SUCCEEDED(rv) && svc) 
00092     rv = svc->AddObserver(this, "profile-do-change", PR_TRUE); // we want to reload the dictionary if the profile switches
00093 
00094   if (NS_FAILED(rv)) return rv;
00095 
00096   Load();
00097   
00098   return NS_OK;
00099 }
00100 
00101 /* void Load (); */
00102 NS_IMETHODIMP mozPersonalDictionary::Load()
00103 {
00104   //FIXME Deinst  -- get dictionary name from prefs;
00105   nsresult res;
00106   nsCOMPtr<nsIFile> theFile;
00107   PRBool dictExists;
00108 
00109   res = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(theFile));
00110   if(NS_FAILED(res)) return res;
00111   if(!theFile)return NS_ERROR_FAILURE;
00112   res = theFile->Append(NS_LITERAL_STRING(MOZ_PERSONAL_DICT_NAME));
00113   if(NS_FAILED(res)) return res;
00114   res = theFile->Exists(&dictExists);
00115   if(NS_FAILED(res)) return res;
00116 
00117   if (!dictExists) {
00118     // Nothing is really wrong...
00119     return NS_OK;
00120   }
00121   
00122   nsCOMPtr<nsIInputStream> inStream;
00123   NS_NewLocalFileInputStream(getter_AddRefs(inStream), theFile);
00124   nsCOMPtr<nsIUnicharInputStream> convStream;
00125   res = NS_NewUTF8ConverterStream(getter_AddRefs(convStream), inStream, 0);
00126   if(NS_FAILED(res)) return res;
00127   
00128   // we're rereading to get rid of the old data  -- we shouldn't have any, but...
00129   mDictionaryTable.Clear();
00130 
00131   PRUnichar c;
00132   PRUint32 nRead;
00133   PRBool done = PR_FALSE;
00134   do{  // read each line of text into the string array.
00135     if( (NS_OK != convStream->Read(&c, 1, &nRead)) || (nRead != 1)) break;
00136     while(!done && ((c == '\n') || (c == '\r'))){
00137       if( (NS_OK != convStream->Read(&c, 1, &nRead)) || (nRead != 1)) done = PR_TRUE;
00138     }
00139     if (!done){ 
00140       nsAutoString word;
00141       while((c != '\n') && (c != '\r') && !done){
00142         word.Append(c);
00143         if( (NS_OK != convStream->Read(&c, 1, &nRead)) || (nRead != 1)) done = PR_TRUE;
00144       }
00145       mDictionaryTable.PutEntry(word.get());
00146     }
00147   } while(!done);
00148   mDirty = PR_FALSE;
00149   
00150   return res;
00151 }
00152 
00153 // A little helper function to add the key to the list.
00154 // This is not threadsafe, and only safe if the consumer does not 
00155 // modify the list.
00156 PR_STATIC_CALLBACK(PLDHashOperator)
00157 AddHostToStringArray(nsUniCharEntry *aEntry, void *aArg)
00158 {
00159   NS_STATIC_CAST(nsStringArray*, aArg)->AppendString(nsDependentString(aEntry->GetKey()));
00160   return PL_DHASH_NEXT;
00161 }
00162 
00163 /* void Save (); */
00164 NS_IMETHODIMP mozPersonalDictionary::Save()
00165 {
00166   nsCOMPtr<nsIFile> theFile;
00167   nsresult res;
00168 
00169   if(!mDirty) return NS_OK;
00170 
00171   //FIXME Deinst  -- get dictionary name from prefs;
00172   res = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(theFile));
00173   if(NS_FAILED(res)) return res;
00174   if(!theFile)return NS_ERROR_FAILURE;
00175   res = theFile->Append(NS_LITERAL_STRING(MOZ_PERSONAL_DICT_NAME));
00176   if(NS_FAILED(res)) return res;
00177 
00178   nsCOMPtr<nsIOutputStream> outStream;
00179   NS_NewLocalFileOutputStream(getter_AddRefs(outStream), theFile, PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE ,0664);
00180 
00181   // get a buffered output stream 4096 bytes big, to optimize writes
00182   nsCOMPtr<nsIOutputStream> bufferedOutputStream;
00183   res = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), outStream, 4096);
00184   if (NS_FAILED(res)) return res;
00185 
00186   nsStringArray array(mDictionaryTable.Count());
00187   mDictionaryTable.EnumerateEntries(AddHostToStringArray, &array);
00188 
00189   PRUint32 bytesWritten;
00190   nsCAutoString utf8Key;
00191   for (PRInt32 i = 0; i < array.Count(); ++i ) {
00192     const nsString *key = array[i];
00193     CopyUTF16toUTF8(*key, utf8Key);
00194 
00195     bufferedOutputStream->Write(utf8Key.get(), utf8Key.Length(), &bytesWritten);
00196     bufferedOutputStream->Write("\n", 1, &bytesWritten);
00197   }
00198   return res;
00199 }
00200 
00201 /* readonly attribute nsIStringEnumerator GetWordList() */
00202 NS_IMETHODIMP mozPersonalDictionary::GetWordList(nsIStringEnumerator **aWords)
00203 {
00204   NS_ENSURE_ARG_POINTER(aWords);
00205   *aWords = nsnull;
00206 
00207   nsStringArray *array = new nsStringArray(mDictionaryTable.Count());
00208   if (!array)
00209     return NS_ERROR_OUT_OF_MEMORY;
00210 
00211   mDictionaryTable.EnumerateEntries(AddHostToStringArray, array);
00212 
00213   array->Sort();
00214 
00215   return NS_NewAdoptingStringEnumerator(aWords, array);
00216 }
00217 
00218 /* boolean Check (in wstring word, in wstring language); */
00219 NS_IMETHODIMP mozPersonalDictionary::Check(const PRUnichar *aWord, const PRUnichar *aLanguage, PRBool *aResult)
00220 {
00221   NS_ENSURE_ARG_POINTER(aWord);
00222   NS_ENSURE_ARG_POINTER(aResult);
00223 
00224   *aResult = (mDictionaryTable.GetEntry(aWord) || mIgnoreTable.GetEntry(aWord));
00225   return NS_OK;
00226 }
00227 
00228 /* void AddWord (in wstring word); */
00229 NS_IMETHODIMP mozPersonalDictionary::AddWord(const PRUnichar *aWord, const PRUnichar *aLang)
00230 {
00231   mDictionaryTable.PutEntry(aWord);
00232   mDirty = PR_TRUE;
00233   return NS_OK;
00234 }
00235 
00236 /* void RemoveWord (in wstring word); */
00237 NS_IMETHODIMP mozPersonalDictionary::RemoveWord(const PRUnichar *aWord, const PRUnichar *aLang)
00238 {
00239   mDictionaryTable.RemoveEntry(aWord);
00240   mDirty = PR_TRUE;
00241   return NS_OK;
00242 }
00243 
00244 /* void IgnoreWord (in wstring word); */
00245 NS_IMETHODIMP mozPersonalDictionary::IgnoreWord(const PRUnichar *aWord)
00246 {
00247   // avoid adding duplicate words to the ignore list
00248   if (aWord && !mIgnoreTable.GetEntry(aWord)) 
00249     mIgnoreTable.PutEntry(aWord);
00250   return NS_OK;
00251 }
00252 
00253 /* void EndSession (); */
00254 NS_IMETHODIMP mozPersonalDictionary::EndSession()
00255 {
00256   Save(); // save any custom words at the end of a spell check session
00257   mIgnoreTable.Clear();
00258   return NS_OK;
00259 }
00260 
00261 /* void AddCorrection (in wstring word, in wstring correction); */
00262 NS_IMETHODIMP mozPersonalDictionary::AddCorrection(const PRUnichar *word, const PRUnichar *correction, const PRUnichar *lang)
00263 {
00264     return NS_ERROR_NOT_IMPLEMENTED;
00265 }
00266 
00267 /* void RemoveCorrection (in wstring word, in wstring correction); */
00268 NS_IMETHODIMP mozPersonalDictionary::RemoveCorrection(const PRUnichar *word, const PRUnichar *correction, const PRUnichar *lang)
00269 {
00270     return NS_ERROR_NOT_IMPLEMENTED;
00271 }
00272 
00273 /* void GetCorrection (in wstring word, [array, size_is (count)] out wstring words, out PRUint32 count); */
00274 NS_IMETHODIMP mozPersonalDictionary::GetCorrection(const PRUnichar *word, PRUnichar ***words, PRUint32 *count)
00275 {
00276     return NS_ERROR_NOT_IMPLEMENTED;
00277 }
00278 
00279 /* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */
00280 NS_IMETHODIMP mozPersonalDictionary::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
00281 {
00282   if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
00283     Load();  // load automatically clears out the existing dictionary table
00284   }
00285 
00286   return NS_OK;
00287 }
00288