blob: ff7971753c7953af139cc47881494398d264764d [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/browser/load_and_localize_file.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/thread_task_runner_handle.h"
#include "extensions/browser/component_extension_resource_manager.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/file_reader.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/extension_l10n_util.h"
#include "extensions/common/extension_resource.h"
#include "extensions/common/file_util.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/message_bundle.h"
#include "ui/base/resource/resource_bundle.h"
namespace extensions {
namespace {
void MaybeLocalizeInBackground(
const ExtensionId& extension_id,
const base::FilePath& extension_path,
const std::string& extension_default_locale,
extension_l10n_util::GzippedMessagesPermission gzip_permission,
std::string* data) {
bool needs_message_substituion =
data->find(extensions::MessageBundle::kMessageBegin) != std::string::npos;
if (!needs_message_substituion)
return;
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
std::unique_ptr<MessageBundle::SubstitutionMap> localization_messages(
file_util::LoadMessageBundleSubstitutionMap(extension_path, extension_id,
extension_default_locale,
gzip_permission));
std::string error;
MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages,
data, &error);
}
// A simple wrapper around MaybeLocalizeInBackground() that returns |data| to
// serve as an adapter for PostTaskAndReply.
std::unique_ptr<std::string> LocalizeComponentResourceInBackground(
std::unique_ptr<std::string> data,
const ExtensionId& extension_id,
const base::FilePath& extension_path,
const std::string& extension_default_locale,
extension_l10n_util::GzippedMessagesPermission gzip_permission) {
MaybeLocalizeInBackground(extension_id, extension_path,
extension_default_locale, gzip_permission,
data.get());
return data;
}
} // namespace
void LoadAndLocalizeResource(const Extension& extension,
const ExtensionResource& resource,
bool localize_file,
LoadAndLocalizeResourceCallback callback) {
DCHECK(!resource.extension_root().empty());
DCHECK(!resource.relative_path().empty());
std::string extension_default_locale;
extension.manifest()->GetString(manifest_keys::kDefaultLocale,
&extension_default_locale);
auto gzip_permission =
extension_l10n_util::GetGzippedMessagesPermissionForExtension(&extension);
// Check whether the resource should be loaded as a component resource (from
// the resource bundle) or read from disk.
int resource_id = 0;
const ComponentExtensionResourceManager*
component_extension_resource_manager =
ExtensionsBrowserClient::Get()
->GetComponentExtensionResourceManager();
if (component_extension_resource_manager &&
component_extension_resource_manager->IsComponentExtensionResource(
resource.extension_root(), resource.relative_path(), &resource_id)) {
auto data = std::make_unique<std::string>(
ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
resource_id));
// We assume this call always succeeds.
constexpr bool kSuccess = true;
if (!localize_file) {
// Even if no localization is necessary, we post the task asynchronously
// so that |callback| is not run re-entrantly.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), kSuccess, std::move(data)));
} else {
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(&LocalizeComponentResourceInBackground,
std::move(data), extension.id(), extension.path(),
extension_default_locale, gzip_permission),
base::BindOnce(std::move(callback), kSuccess));
}
} else {
FileReader::OptionalFileSequenceTask get_file_and_l10n_callback;
if (localize_file) {
get_file_and_l10n_callback = base::BindOnce(
&MaybeLocalizeInBackground, extension.id(), extension.path(),
extension_default_locale, gzip_permission);
}
auto file_reader = base::MakeRefCounted<FileReader>(
resource, std::move(get_file_and_l10n_callback), std::move(callback));
file_reader->Start();
}
}
} // namespace extensions