| OLD | NEW | 
|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/browser/spellcheck_host.h" | 5 #include "chrome/browser/spellcheck_host.h" | 
| 6 | 6 | 
| 7 #include <fcntl.h> | 7 #include <fcntl.h> | 
| 8 | 8 | 
| 9 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" | 
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" | 
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 114     if (language == special_version_string[i].language) { | 114     if (language == special_version_string[i].language) { | 
| 115       versioned_bdict_file_name = | 115       versioned_bdict_file_name = | 
| 116           language + special_version_string[i].version + ".bdic"; | 116           language + special_version_string[i].version + ".bdic"; | 
| 117       break; | 117       break; | 
| 118     } | 118     } | 
| 119   } | 119   } | 
| 120 | 120 | 
| 121   return dict_dir.AppendASCII(versioned_bdict_file_name); | 121   return dict_dir.AppendASCII(versioned_bdict_file_name); | 
| 122 } | 122 } | 
| 123 | 123 | 
| 124 FilePath GetFirstChoiceFilePath(const std::string& language) { |  | 
| 125   FilePath dict_dir; |  | 
| 126   PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); |  | 
| 127   return GetVersionedFileName(language, dict_dir); |  | 
| 128 } |  | 
| 129 |  | 
| 130 FilePath GetFallbackFilePath(const FilePath& first_choice) { |  | 
| 131   FilePath dict_dir; |  | 
| 132   PathService::Get(chrome::DIR_USER_DATA, &dict_dir); |  | 
| 133   return dict_dir.Append(first_choice.BaseName()); |  | 
| 134 } |  | 
| 135 |  | 
| 136 }  // namespace | 124 }  // namespace | 
| 137 | 125 | 
| 138 // Constructed on UI thread. | 126 // Constructed on UI thread. | 
| 139 SpellCheckHost::SpellCheckHost(Observer* observer, | 127 SpellCheckHost::SpellCheckHost(Observer* observer, | 
| 140                                const std::string& language, | 128                                const std::string& language, | 
| 141                                URLRequestContextGetter* request_context_getter) | 129                                URLRequestContextGetter* request_context_getter) | 
| 142     : observer_(observer), | 130     : observer_(observer), | 
| 143       language_(language), | 131       language_(language), | 
| 144       file_(base::kInvalidPlatformFileValue), |  | 
| 145       tried_to_download_(false), | 132       tried_to_download_(false), | 
| 146       request_context_getter_(request_context_getter) { | 133       request_context_getter_(request_context_getter) { | 
| 147   DCHECK(observer_); | 134   DCHECK(observer_); | 
| 148   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 135   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 
| 149 | 136 | 
|  | 137   // TODO(estade): for Windows, we need to fall back to DIR_USER_DATA if | 
|  | 138   // DIR_APP_DICTIONARIES is not writeable. | 
|  | 139   FilePath dict_dir; | 
|  | 140   PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); | 
|  | 141   bdict_file_ = GetVersionedFileName(language, dict_dir); | 
|  | 142 | 
| 150   FilePath personal_file_directory; | 143   FilePath personal_file_directory; | 
| 151   PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); | 144   PathService::Get(chrome::DIR_USER_DATA, &personal_file_directory); | 
| 152   custom_dictionary_file_ = | 145   custom_dictionary_file_ = | 
| 153       personal_file_directory.Append(chrome::kCustomDictionaryFileName); | 146       personal_file_directory.Append(chrome::kCustomDictionaryFileName); | 
| 154 | 147 | 
| 155   bdict_file_path_ = GetFirstChoiceFilePath(language); |  | 
| 156 |  | 
| 157   ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 148   ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 
| 158       NewRunnableMethod(this, &SpellCheckHost::InitializeDictionaryLocation)); | 149       NewRunnableMethod(this, &SpellCheckHost::Initialize)); | 
| 159 } | 150 } | 
| 160 | 151 | 
| 161 SpellCheckHost::~SpellCheckHost() { | 152 SpellCheckHost::~SpellCheckHost() { | 
| 162   if (file_ != base::kInvalidPlatformFileValue) | 153   if (fd_.fd != -1) | 
| 163     base::ClosePlatformFile(file_); | 154     close(fd_.fd); | 
| 164 } | 155 } | 
| 165 | 156 | 
| 166 void SpellCheckHost::UnsetObserver() { | 157 void SpellCheckHost::UnsetObserver() { | 
| 167   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 158   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 
| 168 | 159 | 
| 169   observer_ = NULL; | 160   observer_ = NULL; | 
| 170 } | 161 } | 
| 171 | 162 | 
| 172 void SpellCheckHost::AddWord(const std::string& word) { | 163 void SpellCheckHost::AddWord(const std::string& word) { | 
| 173   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 164   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 
| 174 | 165 | 
| 175   custom_words_.push_back(word); | 166   custom_words_.push_back(word); | 
| 176   ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 167   ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, | 
| 177       NewRunnableMethod(this, | 168       NewRunnableMethod(this, | 
| 178           &SpellCheckHost::WriteWordToCustomDictionary, word)); | 169           &SpellCheckHost::WriteWordToCustomDictionary, word)); | 
| 179   NotificationService::current()->Notify( | 170   NotificationService::current()->Notify( | 
| 180       NotificationType::SPELLCHECK_WORD_ADDED, | 171       NotificationType::SPELLCHECK_WORD_ADDED, | 
| 181       Source<SpellCheckHost>(this), NotificationService::NoDetails()); | 172       Source<SpellCheckHost>(this), NotificationService::NoDetails()); | 
| 182 } | 173 } | 
| 183 | 174 | 
| 184 void SpellCheckHost::InitializeDictionaryLocation() { |  | 
| 185   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |  | 
| 186 |  | 
| 187 #if defined(OS_WIN) |  | 
| 188   // Check if the dictionary exists in the fallback location. If so, use it |  | 
| 189   // rather than downloading anew. |  | 
| 190   FilePath fallback = GetFallbackFilePath(bdict_file_path_); |  | 
| 191   if (!file_util::PathExists(bdict_file_path_) && |  | 
| 192       file_util::PathExists(fallback)) { |  | 
| 193     bdict_file_path_ = fallback; |  | 
| 194   } |  | 
| 195 #endif |  | 
| 196 |  | 
| 197   Initialize(); |  | 
| 198 } |  | 
| 199 |  | 
| 200 void SpellCheckHost::Initialize() { | 175 void SpellCheckHost::Initialize() { | 
| 201   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 176   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 
| 202 | 177 | 
| 203   if (!observer_) | 178   if (!observer_) | 
| 204     return; | 179     return; | 
| 205 | 180 | 
| 206   file_ = base::CreatePlatformFile(bdict_file_path_, | 181   // We set |auto_close| to false because we don't want IPC to close the fd. | 
| 207        base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN, | 182   // We will close it manually in the destructor. | 
| 208        NULL); | 183   fd_ = base::FileDescriptor(open(bdict_file_.value().c_str(), O_RDONLY), | 
|  | 184                              false); | 
| 209 | 185 | 
| 210   // File didn't exist. Download it. | 186   // File didn't exist. Download it. | 
| 211   if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_) { | 187   if (fd_.fd == -1 && !tried_to_download_) { | 
| 212     DownloadDictionary(); | 188     DownloadDictionary(); | 
| 213     return; | 189     return; | 
| 214   } | 190   } | 
| 215 | 191 | 
| 216   if (file_ != base::kInvalidPlatformFileValue) { | 192   if (fd_.fd != -1) { | 
| 217     // Load custom dictionary. | 193     // Load custom dictionary. | 
| 218     std::string contents; | 194     std::string contents; | 
| 219     file_util::ReadFileToString(custom_dictionary_file_, &contents); | 195     file_util::ReadFileToString(custom_dictionary_file_, &contents); | 
| 220     std::vector<std::string> list_of_words; | 196     std::vector<std::string> list_of_words; | 
| 221     SplitString(contents, '\n', &list_of_words); | 197     SplitString(contents, '\n', &list_of_words); | 
| 222     for (size_t i = 0; i < list_of_words.size(); ++i) | 198     for (size_t i = 0; i < list_of_words.size(); ++i) | 
| 223       custom_words_.push_back(list_of_words[i]); | 199       custom_words_.push_back(list_of_words[i]); | 
| 224   } | 200   } | 
| 225 | 201 | 
| 226   ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, | 202   ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, | 
| 227       NewRunnableMethod(this, | 203       NewRunnableMethod(this, | 
| 228           &SpellCheckHost::InformObserverOfInitialization)); | 204           &SpellCheckHost::InformObserverOfInitialization)); | 
| 229 } | 205 } | 
| 230 | 206 | 
| 231 void SpellCheckHost::InformObserverOfInitialization() { | 207 void SpellCheckHost::InformObserverOfInitialization() { | 
| 232   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 208   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 
| 233 | 209 | 
| 234   if (observer_) | 210   if (observer_) | 
| 235     observer_->SpellCheckHostInitialized(); | 211     observer_->SpellCheckHostInitialized(); | 
| 236 } | 212 } | 
| 237 | 213 | 
| 238 void SpellCheckHost::DownloadDictionary() { | 214 void SpellCheckHost::DownloadDictionary() { | 
| 239   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 215   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 
| 240 | 216 | 
| 241   // Determine URL of file to download. | 217   // Determine URL of file to download. | 
| 242   static const char kDownloadServerUrl[] = | 218   static const char kDownloadServerUrl[] = | 
| 243       "http://cache.pack.google.com/edgedl/chrome/dict/"; | 219       "http://cache.pack.google.com/edgedl/chrome/dict/"; | 
| 244   GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8( | 220   GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8( | 
| 245       l10n_util::ToLower(bdict_file_path_.BaseName().ToWStringHack()))); | 221       l10n_util::ToLower(bdict_file_.BaseName().ToWStringHack()))); | 
| 246   fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); | 222   fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this)); | 
| 247   fetcher_->set_request_context(request_context_getter_.get()); | 223   fetcher_->set_request_context(request_context_getter_.get()); | 
| 248   tried_to_download_ = true; | 224   tried_to_download_ = true; | 
| 249   fetcher_->Start(); | 225   fetcher_->Start(); | 
| 250 } | 226 } | 
| 251 | 227 | 
| 252 void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) { | 228 void SpellCheckHost::WriteWordToCustomDictionary(const std::string& word) { | 
| 253   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 229   DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 
| 254 | 230 | 
| 255   // Stored in UTF-8. | 231   // Stored in UTF-8. | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
| 280   // There's the small chance that we might see a 200 status code for a body | 256   // There's the small chance that we might see a 200 status code for a body | 
| 281   // that represents some form of failure. | 257   // that represents some form of failure. | 
| 282   if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || | 258   if (data.size() < 4 || data[0] != 'B' || data[1] != 'D' || data[2] != 'i' || | 
| 283       data[3] != 'c') { | 259       data[3] != 'c') { | 
| 284     LOG(ERROR) << "Failure to download dictionary."; | 260     LOG(ERROR) << "Failure to download dictionary."; | 
| 285     Initialize(); | 261     Initialize(); | 
| 286     return; | 262     return; | 
| 287   } | 263   } | 
| 288 | 264 | 
| 289   size_t bytes_written = | 265   size_t bytes_written = | 
| 290       file_util::WriteFile(bdict_file_path_, data.data(), data.length()); | 266       file_util::WriteFile(bdict_file_, data.data(), data.length()); | 
| 291   if (bytes_written != data.length()) { | 267   if (bytes_written != data.length()) { | 
| 292     bool success = false; | 268     LOG(ERROR) << "Failure to save dictionary."; | 
| 293 #if defined(OS_WIN) | 269     // To avoid trying to load a partially saved dictionary, shortcut the | 
| 294     bdict_file_path_ = GetFallbackFilePath(bdict_file_path_); | 270     // Initialize() call. | 
| 295     bytes_written = | 271     ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, | 
| 296         file_util::WriteFile(GetFallbackFilePath(bdict_file_path_), | 272         NewRunnableMethod(this, | 
| 297                                                  data.data(), data.length()); | 273             &SpellCheckHost::InformObserverOfInitialization)); | 
| 298     if (bytes_written == data.length()) | 274     return; | 
| 299       success = true; |  | 
| 300 #endif |  | 
| 301 |  | 
| 302     if (!success) { |  | 
| 303       LOG(ERROR) << "Failure to save dictionary."; |  | 
| 304       // To avoid trying to load a partially saved dictionary, shortcut the |  | 
| 305       // Initialize() call. |  | 
| 306       ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |  | 
| 307           NewRunnableMethod(this, |  | 
| 308               &SpellCheckHost::InformObserverOfInitialization)); |  | 
| 309       return; |  | 
| 310     } |  | 
| 311   } | 275   } | 
| 312 | 276 | 
| 313   Initialize(); | 277   Initialize(); | 
| 314 } | 278 } | 
| OLD | NEW | 
|---|