PageRenderTime 37ms CodeModel.GetById 17ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/extensions/spellcheck/src/mozPersonalDictionary.cpp

http://github.com/zpao/v8monkey
C++ | 299 lines | 182 code | 50 blank | 67 comment | 43 complexity | a29252b65ad45b35e798b622cfcdf360 MD5 | raw file
  1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2/* ***** BEGIN LICENSE BLOCK *****
  3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4 *
  5 * The contents of this file are subject to the Mozilla Public License Version
  6 * 1.1 (the "License"); you may not use this file except in compliance with
  7 * the License. You may obtain a copy of the License at
  8 * http://www.mozilla.org/MPL/
  9 *
 10 * Software distributed under the License is distributed on an "AS IS" basis,
 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 12 * for the specific language governing rights and limitations under the
 13 * License.
 14 *
 15 * The Original Code is Mozilla Spellchecker Component.
 16 *
 17 * The Initial Developer of the Original Code is
 18 * David Einstein.
 19 * Portions created by the Initial Developer are Copyright (C) 2001
 20 * the Initial Developer. All Rights Reserved.
 21 *
 22 * Contributor(s): David Einstein <Deinst@world.std.com>
 23 *
 24 * Alternatively, the contents of this file may be used under the terms of
 25 * either the GNU General Public License Version 2 or later (the "GPL"), or
 26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 27 * in which case the provisions of the GPL or the LGPL are applicable instead
 28 * of those above. If you wish to allow use of your version of this file only
 29 * under the terms of either the GPL or the LGPL, and not to allow others to
 30 * use your version of this file under the terms of the MPL, indicate your
 31 * decision by deleting the provisions above and replace them with the notice
 32 * and other provisions required by the GPL or the LGPL. If you do not delete
 33 * the provisions above, a recipient may use your version of this file under
 34 * the terms of any one of the MPL, the GPL or the LGPL.
 35 *
 36 * ***** END LICENSE BLOCK ***** */
 37
 38#include "mozPersonalDictionary.h"
 39#include "nsIUnicharInputStream.h"
 40#include "nsReadableUtils.h"
 41#include "nsIFile.h"
 42#include "nsAppDirectoryServiceDefs.h"
 43#include "nsICharsetConverterManager.h"
 44#include "nsICharsetAlias.h"
 45#include "nsIObserverService.h"
 46#include "nsIPrefService.h"
 47#include "nsIPrefBranch.h"
 48#include "nsIWeakReference.h"
 49#include "nsCRT.h"
 50#include "nsNetUtil.h"
 51#include "nsStringEnumerator.h"
 52#include "nsUnicharInputStream.h"
 53
 54#define MOZ_PERSONAL_DICT_NAME "persdict.dat"
 55
 56const int kMaxWordLen=256;
 57
 58/**
 59 * This is the most braindead implementation of a personal dictionary possible.
 60 * There is not much complexity needed, though.  It could be made much faster,
 61 *  and probably should, but I don't see much need for more in terms of interface.
 62 *
 63 * Allowing personal words to be associated with only certain dictionaries maybe.
 64 *
 65 * TODO:
 66 * Implement the suggestion record.
 67 */
 68
 69
 70NS_IMPL_CYCLE_COLLECTING_ADDREF(mozPersonalDictionary)
 71NS_IMPL_CYCLE_COLLECTING_RELEASE(mozPersonalDictionary)
 72
 73NS_INTERFACE_MAP_BEGIN(mozPersonalDictionary)
 74  NS_INTERFACE_MAP_ENTRY(mozIPersonalDictionary)
 75  NS_INTERFACE_MAP_ENTRY(nsIObserver)
 76  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 77  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozIPersonalDictionary)
 78  NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozPersonalDictionary)
 79NS_INTERFACE_MAP_END
 80
 81NS_IMPL_CYCLE_COLLECTION_1(mozPersonalDictionary, mEncoder)
 82
 83mozPersonalDictionary::mozPersonalDictionary()
 84 : mDirty(false)
 85{
 86}
 87
 88mozPersonalDictionary::~mozPersonalDictionary()
 89{
 90}
 91
 92nsresult mozPersonalDictionary::Init()
 93{
 94  if (!mDictionaryTable.Init() || !mIgnoreTable.Init())
 95    return NS_ERROR_OUT_OF_MEMORY;
 96
 97  nsresult rv;
 98  nsCOMPtr<nsIObserverService> svc = 
 99           do_GetService("@mozilla.org/observer-service;1", &rv);
100   
101  if (NS_SUCCEEDED(rv) && svc) 
102    rv = svc->AddObserver(this, "profile-do-change", true); // we want to reload the dictionary if the profile switches
103
104  if (NS_FAILED(rv)) return rv;
105
106  Load();
107  
108  return NS_OK;
109}
110
111/* void Load (); */
112NS_IMETHODIMP mozPersonalDictionary::Load()
113{
114  //FIXME Deinst  -- get dictionary name from prefs;
115  nsresult res;
116  nsCOMPtr<nsIFile> theFile;
117  bool dictExists;
118
119  res = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(theFile));
120  if(NS_FAILED(res)) return res;
121  if(!theFile)return NS_ERROR_FAILURE;
122  res = theFile->Append(NS_LITERAL_STRING(MOZ_PERSONAL_DICT_NAME));
123  if(NS_FAILED(res)) return res;
124  res = theFile->Exists(&dictExists);
125  if(NS_FAILED(res)) return res;
126
127  if (!dictExists) {
128    // Nothing is really wrong...
129    return NS_OK;
130  }
131  
132  nsCOMPtr<nsIInputStream> inStream;
133  NS_NewLocalFileInputStream(getter_AddRefs(inStream), theFile);
134
135  nsCOMPtr<nsIUnicharInputStream> convStream;
136  res = nsSimpleUnicharStreamFactory::GetInstance()->
137    CreateInstanceFromUTF8Stream(inStream, getter_AddRefs(convStream));
138  if(NS_FAILED(res)) return res;
139  
140  // we're rereading to get rid of the old data  -- we shouldn't have any, but...
141  mDictionaryTable.Clear();
142
143  PRUnichar c;
144  PRUint32 nRead;
145  bool done = false;
146  do{  // read each line of text into the string array.
147    if( (NS_OK != convStream->Read(&c, 1, &nRead)) || (nRead != 1)) break;
148    while(!done && ((c == '\n') || (c == '\r'))){
149      if( (NS_OK != convStream->Read(&c, 1, &nRead)) || (nRead != 1)) done = true;
150    }
151    if (!done){ 
152      nsAutoString word;
153      while((c != '\n') && (c != '\r') && !done){
154        word.Append(c);
155        if( (NS_OK != convStream->Read(&c, 1, &nRead)) || (nRead != 1)) done = true;
156      }
157      mDictionaryTable.PutEntry(word.get());
158    }
159  } while(!done);
160  mDirty = false;
161  
162  return res;
163}
164
165// A little helper function to add the key to the list.
166// This is not threadsafe, and only safe if the consumer does not 
167// modify the list.
168static PLDHashOperator
169AddHostToStringArray(nsUnicharPtrHashKey *aEntry, void *aArg)
170{
171  static_cast<nsTArray<nsString>*>(aArg)->AppendElement(nsDependentString(aEntry->GetKey()));
172  return PL_DHASH_NEXT;
173}
174
175/* void Save (); */
176NS_IMETHODIMP mozPersonalDictionary::Save()
177{
178  nsCOMPtr<nsIFile> theFile;
179  nsresult res;
180
181  if(!mDirty) return NS_OK;
182
183  //FIXME Deinst  -- get dictionary name from prefs;
184  res = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(theFile));
185  if(NS_FAILED(res)) return res;
186  if(!theFile)return NS_ERROR_FAILURE;
187  res = theFile->Append(NS_LITERAL_STRING(MOZ_PERSONAL_DICT_NAME));
188  if(NS_FAILED(res)) return res;
189
190  nsCOMPtr<nsIOutputStream> outStream;
191  NS_NewLocalFileOutputStream(getter_AddRefs(outStream), theFile, PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE ,0664);
192
193  // get a buffered output stream 4096 bytes big, to optimize writes
194  nsCOMPtr<nsIOutputStream> bufferedOutputStream;
195  res = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), outStream, 4096);
196  if (NS_FAILED(res)) return res;
197
198  nsTArray<nsString> array(mDictionaryTable.Count());
199  mDictionaryTable.EnumerateEntries(AddHostToStringArray, &array);
200
201  PRUint32 bytesWritten;
202  nsCAutoString utf8Key;
203  for (PRUint32 i = 0; i < array.Length(); ++i ) {
204    CopyUTF16toUTF8(array[i], utf8Key);
205
206    bufferedOutputStream->Write(utf8Key.get(), utf8Key.Length(), &bytesWritten);
207    bufferedOutputStream->Write("\n", 1, &bytesWritten);
208  }
209  return res;
210}
211
212/* readonly attribute nsIStringEnumerator GetWordList() */
213NS_IMETHODIMP mozPersonalDictionary::GetWordList(nsIStringEnumerator **aWords)
214{
215  NS_ENSURE_ARG_POINTER(aWords);
216  *aWords = nsnull;
217
218  nsTArray<nsString> *array = new nsTArray<nsString>(mDictionaryTable.Count());
219  if (!array)
220    return NS_ERROR_OUT_OF_MEMORY;
221
222  mDictionaryTable.EnumerateEntries(AddHostToStringArray, array);
223
224  array->Sort();
225
226  return NS_NewAdoptingStringEnumerator(aWords, array);
227}
228
229/* boolean Check (in wstring word, in wstring language); */
230NS_IMETHODIMP mozPersonalDictionary::Check(const PRUnichar *aWord, const PRUnichar *aLanguage, bool *aResult)
231{
232  NS_ENSURE_ARG_POINTER(aWord);
233  NS_ENSURE_ARG_POINTER(aResult);
234
235  *aResult = (mDictionaryTable.GetEntry(aWord) || mIgnoreTable.GetEntry(aWord));
236  return NS_OK;
237}
238
239/* void AddWord (in wstring word); */
240NS_IMETHODIMP mozPersonalDictionary::AddWord(const PRUnichar *aWord, const PRUnichar *aLang)
241{
242  mDictionaryTable.PutEntry(aWord);
243  mDirty = true;
244  return NS_OK;
245}
246
247/* void RemoveWord (in wstring word); */
248NS_IMETHODIMP mozPersonalDictionary::RemoveWord(const PRUnichar *aWord, const PRUnichar *aLang)
249{
250  mDictionaryTable.RemoveEntry(aWord);
251  mDirty = true;
252  return NS_OK;
253}
254
255/* void IgnoreWord (in wstring word); */
256NS_IMETHODIMP mozPersonalDictionary::IgnoreWord(const PRUnichar *aWord)
257{
258  // avoid adding duplicate words to the ignore list
259  if (aWord && !mIgnoreTable.GetEntry(aWord)) 
260    mIgnoreTable.PutEntry(aWord);
261  return NS_OK;
262}
263
264/* void EndSession (); */
265NS_IMETHODIMP mozPersonalDictionary::EndSession()
266{
267  Save(); // save any custom words at the end of a spell check session
268  mIgnoreTable.Clear();
269  return NS_OK;
270}
271
272/* void AddCorrection (in wstring word, in wstring correction); */
273NS_IMETHODIMP mozPersonalDictionary::AddCorrection(const PRUnichar *word, const PRUnichar *correction, const PRUnichar *lang)
274{
275    return NS_ERROR_NOT_IMPLEMENTED;
276}
277
278/* void RemoveCorrection (in wstring word, in wstring correction); */
279NS_IMETHODIMP mozPersonalDictionary::RemoveCorrection(const PRUnichar *word, const PRUnichar *correction, const PRUnichar *lang)
280{
281    return NS_ERROR_NOT_IMPLEMENTED;
282}
283
284/* void GetCorrection (in wstring word, [array, size_is (count)] out wstring words, out PRUint32 count); */
285NS_IMETHODIMP mozPersonalDictionary::GetCorrection(const PRUnichar *word, PRUnichar ***words, PRUint32 *count)
286{
287    return NS_ERROR_NOT_IMPLEMENTED;
288}
289
290/* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */
291NS_IMETHODIMP mozPersonalDictionary::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
292{
293  if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
294    Load();  // load automatically clears out the existing dictionary table
295  }
296
297  return NS_OK;
298}
299