// Copyright 2013 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/common/manifest_handlers/requirements_info.h"
#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/manifest_constants.h"
namespace extensions {
namespace keys = manifest_keys;
namespace errors = manifest_errors;
RequirementsInfo::RequirementsInfo(const Manifest* manifest)
: webgl(false),
css3d(false),
npapi(false) {
// Before parsing requirements from the manifest, automatically default the
// NPAPI plugin requirement based on whether it includes NPAPI plugins.
const base::ListValue* list_value = NULL;
npapi = manifest->GetList(keys::kPlugins, &list_value) &&
!list_value->empty();
}
RequirementsInfo::~RequirementsInfo() {
}
// static
const RequirementsInfo& RequirementsInfo::GetRequirements(
const Extension* extension) {
RequirementsInfo* info = static_cast<RequirementsInfo*>(
extension->GetManifestData(keys::kRequirements));
// We should be guaranteed to have requirements, since they are parsed for all
// extension types.
CHECK(info);
return *info;
}
RequirementsHandler::RequirementsHandler() {
}
RequirementsHandler::~RequirementsHandler() {
}
const std::vector<std::string> RequirementsHandler::PrerequisiteKeys() const {
return SingleKey(keys::kPlugins);
}
const std::vector<std::string> RequirementsHandler::Keys() const {
return SingleKey(keys::kRequirements);
}
bool RequirementsHandler::AlwaysParseForType(Manifest::Type type) const {
return true;
}
bool RequirementsHandler::Parse(Extension* extension, string16* error) {
scoped_ptr<RequirementsInfo> requirements(
new RequirementsInfo(extension->manifest()));
if (!extension->manifest()->HasKey(keys::kRequirements)) {
extension->SetManifestData(keys::kRequirements, requirements.release());
return true;
}
const base::DictionaryValue* requirements_value = NULL;
if (!extension->manifest()->GetDictionary(keys::kRequirements,
&requirements_value)) {
*error = ASCIIToUTF16(errors::kInvalidRequirements);
return false;
}
for (base::DictionaryValue::Iterator iter(*requirements_value);
!iter.IsAtEnd();
iter.Advance()) {
const base::DictionaryValue* requirement_value;
if (!iter.value().GetAsDictionary(&requirement_value)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidRequirement, iter.key());
return false;
}
if (iter.key() == "plugins") {
for (base::DictionaryValue::Iterator plugin_iter(*requirement_value);
!plugin_iter.IsAtEnd(); plugin_iter.Advance()) {
bool plugin_required = false;
if (!plugin_iter.value().GetAsBoolean(&plugin_required)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidRequirement, iter.key());
return false;
}
if (plugin_iter.key() == "npapi") {
requirements->npapi = plugin_required;
} else {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidRequirement, iter.key());
return false;
}
}
} else if (iter.key() == "3D") {
const base::ListValue* features = NULL;
if (!requirement_value->GetListWithoutPathExpansion("features",
&features) ||
!features) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidRequirement, iter.key());
return false;
}
for (base::ListValue::const_iterator feature_iter = features->begin();
feature_iter != features->end(); ++feature_iter) {
std::string feature;
if ((*feature_iter)->GetAsString(&feature)) {
if (feature == "webgl") {
requirements->webgl = true;
} else if (feature == "css3d") {
requirements->css3d = true;
} else {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidRequirement, iter.key());
return false;
}
}
}
} else {
*error = ASCIIToUTF16(errors::kInvalidRequirements);
return false;
}
}
extension->SetManifestData(keys::kRequirements, requirements.release());
return true;
}
} // namespace extensions