blob: 6a7423055fca2c3755605d992aee9c300f53320c [file] [log] [blame]
// Copyright 2014 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 "content/common/android/gin_java_bridge_value.h"
namespace content {
namespace {
// The magic value is only used to prevent accidental attempts of reading
// GinJavaBridgeValue from a random BinaryValue. GinJavaBridgeValue is not
// intended for scenarios where with BinaryValues are being used for anything
// else than holding GinJavaBridgeValues. If a need for such scenario ever
// emerges, the best solution would be to extend GinJavaBridgeValue to be able
// to wrap raw BinaryValues.
const uint32_t kHeaderMagic = 0xBEEFCAFE;
#pragma pack(push, 4)
struct Header : public base::Pickle::Header {
uint32_t magic;
int32_t type;
};
#pragma pack(pop)
}
// static
std::unique_ptr<base::BinaryValue> GinJavaBridgeValue::CreateUndefinedValue() {
GinJavaBridgeValue gin_value(TYPE_UNDEFINED);
return gin_value.SerializeToBinaryValue();
}
// static
std::unique_ptr<base::BinaryValue> GinJavaBridgeValue::CreateNonFiniteValue(
float in_value) {
GinJavaBridgeValue gin_value(TYPE_NONFINITE);
gin_value.pickle_.WriteFloat(in_value);
return gin_value.SerializeToBinaryValue();
}
// static
std::unique_ptr<base::BinaryValue> GinJavaBridgeValue::CreateNonFiniteValue(
double in_value) {
return CreateNonFiniteValue(static_cast<float>(in_value));
}
// static
std::unique_ptr<base::BinaryValue> GinJavaBridgeValue::CreateObjectIDValue(
int32_t in_value) {
GinJavaBridgeValue gin_value(TYPE_OBJECT_ID);
gin_value.pickle_.WriteInt(in_value);
return gin_value.SerializeToBinaryValue();
}
// static
bool GinJavaBridgeValue::ContainsGinJavaBridgeValue(const base::Value* value) {
if (!value->IsType(base::Value::TYPE_BINARY))
return false;
const base::BinaryValue* binary_value =
reinterpret_cast<const base::BinaryValue*>(value);
if (binary_value->GetSize() < sizeof(Header))
return false;
base::Pickle pickle(binary_value->GetBuffer(), binary_value->GetSize());
// Broken binary value: payload or header size is wrong
if (!pickle.data() || pickle.size() - pickle.payload_size() != sizeof(Header))
return false;
Header* header = pickle.headerT<Header>();
return (header->magic == kHeaderMagic &&
header->type >= TYPE_FIRST_VALUE && header->type < TYPE_LAST_VALUE);
}
// static
std::unique_ptr<const GinJavaBridgeValue> GinJavaBridgeValue::FromValue(
const base::Value* value) {
return std::unique_ptr<const GinJavaBridgeValue>(
value->IsType(base::Value::TYPE_BINARY)
? new GinJavaBridgeValue(
reinterpret_cast<const base::BinaryValue*>(value))
: NULL);
}
GinJavaBridgeValue::Type GinJavaBridgeValue::GetType() const {
const Header* header = pickle_.headerT<Header>();
DCHECK(header->type >= TYPE_FIRST_VALUE && header->type < TYPE_LAST_VALUE);
return static_cast<Type>(header->type);
}
bool GinJavaBridgeValue::IsType(Type type) const {
return GetType() == type;
}
bool GinJavaBridgeValue::GetAsNonFinite(float* out_value) const {
if (GetType() == TYPE_NONFINITE) {
base::PickleIterator iter(pickle_);
return iter.ReadFloat(out_value);
} else {
return false;
}
}
bool GinJavaBridgeValue::GetAsObjectID(int32_t* out_object_id) const {
if (GetType() == TYPE_OBJECT_ID) {
base::PickleIterator iter(pickle_);
return iter.ReadInt(out_object_id);
} else {
return false;
}
}
GinJavaBridgeValue::GinJavaBridgeValue(Type type) :
pickle_(sizeof(Header)) {
Header* header = pickle_.headerT<Header>();
header->magic = kHeaderMagic;
header->type = type;
}
GinJavaBridgeValue::GinJavaBridgeValue(const base::BinaryValue* value)
: pickle_(value->GetBuffer(), value->GetSize()) {
DCHECK(ContainsGinJavaBridgeValue(value));
}
std::unique_ptr<base::BinaryValue>
GinJavaBridgeValue::SerializeToBinaryValue() {
return base::BinaryValue::CreateWithCopiedBuffer(
reinterpret_cast<const char*>(pickle_.data()), pickle_.size());
}
} // namespace content