This source file includes following definitions.
- CloseDictionary
- SaveDictionaryData
- file
- weak_ptr_factory_
- Load
- RetryDownloadDictionary
- IsReady
- GetDictionaryFile
- GetLanguage
- IsUsingPlatformChecker
- AddObserver
- RemoveObserver
- IsDownloadInProgress
- IsDownloadFailure
- OnURLFetchComplete
- GetDictionaryURL
- DownloadDictionary
- OpenDictionaryFile
- InitializeDictionaryLocation
- InitializeDictionaryLocationComplete
- SaveDictionaryDataComplete
- InformListenersOfInitialization
- InformListenersOfDownloadFailure
#include "chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h"
#include "base/file_util.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "chrome/browser/spellchecker/spellcheck_platform_mac.h"
#include "chrome/browser/spellchecker/spellcheck_service.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/spellcheck_common.h"
#include "chrome/common/spellcheck_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context_getter.h"
#include "third_party/hunspell/google/bdict.h"
#include "url/gurl.h"
using content::BrowserThread;
namespace {
void CloseDictionary(base::File file) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
file.Close();
}
bool SaveDictionaryData(scoped_ptr<std::string> data,
const base::FilePath& path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
size_t bytes_written =
base::WriteFile(path, data->data(), data->length());
if (bytes_written != data->length()) {
bool success = false;
#if defined(OS_WIN)
base::FilePath dict_dir;
PathService::Get(chrome::DIR_USER_DATA, &dict_dir);
base::FilePath fallback_file_path =
dict_dir.Append(path.BaseName());
bytes_written =
base::WriteFile(fallback_file_path, data->data(), data->length());
if (bytes_written == data->length())
success = true;
#endif
if (!success) {
base::DeleteFile(path, false);
return false;
}
}
return true;
}
}
SpellcheckHunspellDictionary::DictionaryFile::DictionaryFile() {
}
SpellcheckHunspellDictionary::DictionaryFile::~DictionaryFile() {
if (file.IsValid()) {
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
base::Bind(&CloseDictionary, Passed(&file)));
}
}
SpellcheckHunspellDictionary::DictionaryFile::DictionaryFile(RValue other)
: path(other.object->path),
file(other.object->file.Pass()) {
}
SpellcheckHunspellDictionary::DictionaryFile&
SpellcheckHunspellDictionary::DictionaryFile::operator=(RValue other) {
if (this != other.object) {
path = other.object->path;
file = other.object->file.Pass();
}
return *this;
}
SpellcheckHunspellDictionary::SpellcheckHunspellDictionary(
const std::string& language,
net::URLRequestContextGetter* request_context_getter,
SpellcheckService* spellcheck_service)
: language_(language),
use_platform_spellchecker_(false),
request_context_getter_(request_context_getter),
spellcheck_service_(spellcheck_service),
download_status_(DOWNLOAD_NONE),
weak_ptr_factory_(this) {
}
SpellcheckHunspellDictionary::~SpellcheckHunspellDictionary() {
}
void SpellcheckHunspellDictionary::Load() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
#if defined(OS_MACOSX)
if (spellcheck_mac::SpellCheckerAvailable() &&
spellcheck_mac::PlatformSupportsLanguage(language_)) {
use_platform_spellchecker_ = true;
spellcheck_mac::SetLanguage(language_);
base::MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(
&SpellcheckHunspellDictionary::InformListenersOfInitialization,
weak_ptr_factory_.GetWeakPtr()));
return;
}
#endif
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::FILE,
FROM_HERE,
base::Bind(&InitializeDictionaryLocation, language_),
base::Bind(
&SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete,
weak_ptr_factory_.GetWeakPtr()));
}
void SpellcheckHunspellDictionary::RetryDownloadDictionary(
net::URLRequestContextGetter* request_context_getter) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
request_context_getter_ = request_context_getter;
DownloadDictionary(GetDictionaryURL());
}
bool SpellcheckHunspellDictionary::IsReady() const {
return GetDictionaryFile() !=
base::kInvalidPlatformFileValue || IsUsingPlatformChecker();
}
base::PlatformFile SpellcheckHunspellDictionary::GetDictionaryFile() const {
return dictionary_file_.file.GetPlatformFile();
}
const std::string& SpellcheckHunspellDictionary::GetLanguage() const {
return language_;
}
bool SpellcheckHunspellDictionary::IsUsingPlatformChecker() const {
return use_platform_spellchecker_;
}
void SpellcheckHunspellDictionary::AddObserver(Observer* observer) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
observers_.AddObserver(observer);
}
void SpellcheckHunspellDictionary::RemoveObserver(Observer* observer) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
observers_.RemoveObserver(observer);
}
bool SpellcheckHunspellDictionary::IsDownloadInProgress() {
return download_status_ == DOWNLOAD_IN_PROGRESS;
}
bool SpellcheckHunspellDictionary::IsDownloadFailure() {
return download_status_ == DOWNLOAD_FAILED;
}
void SpellcheckHunspellDictionary::OnURLFetchComplete(
const net::URLFetcher* source) {
DCHECK(source);
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
scoped_ptr<net::URLFetcher> fetcher_destructor(fetcher_.release());
if ((source->GetResponseCode() / 100) != 2) {
InformListenersOfDownloadFailure();
return;
}
scoped_ptr<std::string> data(new std::string);
source->GetResponseAsString(data.get());
if (data->size() < 4 || data->compare(0, 4, "BDic") != 0) {
InformListenersOfDownloadFailure();
return;
}
if (!hunspell::BDict::Verify(data->data(), data->size())) {
SaveDictionaryDataComplete(false);
return;
}
BrowserThread::PostTaskAndReplyWithResult<bool>(
BrowserThread::FILE,
FROM_HERE,
base::Bind(&SaveDictionaryData,
base::Passed(&data),
dictionary_file_.path),
base::Bind(&SpellcheckHunspellDictionary::SaveDictionaryDataComplete,
weak_ptr_factory_.GetWeakPtr()));
}
GURL SpellcheckHunspellDictionary::GetDictionaryURL() {
static const char kDownloadServerUrl[] =
"http://cache.pack.google.com/edgedl/chrome/dict/";
std::string bdict_file = dictionary_file_.path.BaseName().MaybeAsASCII();
DCHECK(!bdict_file.empty());
return GURL(std::string(kDownloadServerUrl) +
StringToLowerASCII(bdict_file));
}
void SpellcheckHunspellDictionary::DownloadDictionary(GURL url) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(request_context_getter_);
download_status_ = DOWNLOAD_IN_PROGRESS;
FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryDownloadBegin());
fetcher_.reset(net::URLFetcher::Create(url, net::URLFetcher::GET, this));
fetcher_->SetRequestContext(request_context_getter_);
fetcher_->SetLoadFlags(
net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES);
fetcher_->Start();
request_context_getter_ = NULL;
}
SpellcheckHunspellDictionary::DictionaryFile
SpellcheckHunspellDictionary::OpenDictionaryFile(const base::FilePath& path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DictionaryFile dictionary;
#if defined(OS_WIN)
base::FilePath user_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_dir);
base::FilePath fallback = user_dir.Append(path.BaseName());
if (!base::PathExists(path) && base::PathExists(fallback))
dictionary.path = fallback;
else
dictionary.path = path;
#else
dictionary.path = path;
#endif
bool bdict_is_valid;
{
base::MemoryMappedFile map;
bdict_is_valid =
base::PathExists(dictionary.path) &&
map.Initialize(dictionary.path) &&
hunspell::BDict::Verify(reinterpret_cast<const char*>(map.data()),
map.length());
}
if (bdict_is_valid) {
dictionary.file.Initialize(dictionary.path,
base::File::FLAG_READ | base::File::FLAG_OPEN);
} else {
base::DeleteFile(dictionary.path, false);
}
return dictionary.Pass();
}
SpellcheckHunspellDictionary::DictionaryFile
SpellcheckHunspellDictionary::InitializeDictionaryLocation(
const std::string& language) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
base::FilePath dict_dir;
PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir);
base::FilePath dict_path =
chrome::spellcheck_common::GetVersionedFileName(language, dict_dir);
return OpenDictionaryFile(dict_path);
}
void SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete(
DictionaryFile file) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
dictionary_file_ = file.Pass();
if (!dictionary_file_.file.IsValid()) {
if (spellcheck_service_->SignalStatusEvent(
SpellcheckService::BDICT_CORRUPTED)) {
request_context_getter_ = NULL;
}
if (request_context_getter_) {
DownloadDictionary(GetDictionaryURL());
return;
}
}
InformListenersOfInitialization();
}
void SpellcheckHunspellDictionary::SaveDictionaryDataComplete(
bool dictionary_saved) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (dictionary_saved) {
download_status_ = DOWNLOAD_NONE;
FOR_EACH_OBSERVER(Observer,
observers_,
OnHunspellDictionaryDownloadSuccess());
Load();
} else {
InformListenersOfDownloadFailure();
InformListenersOfInitialization();
}
}
void SpellcheckHunspellDictionary::InformListenersOfInitialization() {
FOR_EACH_OBSERVER(Observer, observers_, OnHunspellDictionaryInitialized());
}
void SpellcheckHunspellDictionary::InformListenersOfDownloadFailure() {
download_status_ = DOWNLOAD_FAILED;
FOR_EACH_OBSERVER(Observer,
observers_,
OnHunspellDictionaryDownloadFailure());
}