1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/common/android/gin_java_bridge_value.h"
6
7namespace content {
8
9namespace {
10
11// The magic value is only used to prevent accidental attempts of reading
12// GinJavaBridgeValue from a random BinaryValue.  GinJavaBridgeValue is not
13// intended for scenarios where with BinaryValues are being used for anything
14// else than holding GinJavaBridgeValues.  If a need for such scenario ever
15// emerges, the best solution would be to extend GinJavaBridgeValue to be able
16// to wrap raw BinaryValues.
17const uint32 kHeaderMagic = 0xBEEFCAFE;
18
19#pragma pack(push, 4)
20struct Header : public Pickle::Header {
21  uint32 magic;
22  int32 type;
23};
24#pragma pack(pop)
25
26}
27
28// static
29scoped_ptr<base::BinaryValue> GinJavaBridgeValue::CreateUndefinedValue() {
30  GinJavaBridgeValue gin_value(TYPE_UNDEFINED);
31  return make_scoped_ptr(gin_value.SerializeToBinaryValue());
32}
33
34// static
35scoped_ptr<base::BinaryValue> GinJavaBridgeValue::CreateNonFiniteValue(
36    float in_value) {
37  GinJavaBridgeValue gin_value(TYPE_NONFINITE);
38  gin_value.pickle_.WriteFloat(in_value);
39  return make_scoped_ptr(gin_value.SerializeToBinaryValue());
40}
41
42// static
43scoped_ptr<base::BinaryValue> GinJavaBridgeValue::CreateNonFiniteValue(
44    double in_value) {
45  return CreateNonFiniteValue(static_cast<float>(in_value)).Pass();
46}
47
48// static
49scoped_ptr<base::BinaryValue> GinJavaBridgeValue::CreateObjectIDValue(
50    int32 in_value) {
51  GinJavaBridgeValue gin_value(TYPE_OBJECT_ID);
52  gin_value.pickle_.WriteInt(in_value);
53  return make_scoped_ptr(gin_value.SerializeToBinaryValue());
54}
55
56// static
57bool GinJavaBridgeValue::ContainsGinJavaBridgeValue(const base::Value* value) {
58  if (!value->IsType(base::Value::TYPE_BINARY))
59    return false;
60  const base::BinaryValue* binary_value =
61      reinterpret_cast<const base::BinaryValue*>(value);
62  if (binary_value->GetSize() < sizeof(Header))
63    return false;
64  Pickle pickle(binary_value->GetBuffer(), binary_value->GetSize());
65  // Broken binary value: payload or header size is wrong
66  if (!pickle.data() || pickle.size() - pickle.payload_size() != sizeof(Header))
67    return false;
68  Header* header = pickle.headerT<Header>();
69  return (header->magic == kHeaderMagic &&
70          header->type >= TYPE_FIRST_VALUE && header->type < TYPE_LAST_VALUE);
71}
72
73// static
74scoped_ptr<const GinJavaBridgeValue> GinJavaBridgeValue::FromValue(
75    const base::Value* value) {
76  return scoped_ptr<const GinJavaBridgeValue>(
77      value->IsType(base::Value::TYPE_BINARY)
78          ? new GinJavaBridgeValue(
79                reinterpret_cast<const base::BinaryValue*>(value))
80          : NULL);
81}
82
83GinJavaBridgeValue::Type GinJavaBridgeValue::GetType() const {
84  const Header* header = pickle_.headerT<Header>();
85  DCHECK(header->type >= TYPE_FIRST_VALUE && header->type < TYPE_LAST_VALUE);
86  return static_cast<Type>(header->type);
87}
88
89bool GinJavaBridgeValue::IsType(Type type) const {
90  return GetType() == type;
91}
92
93bool GinJavaBridgeValue::GetAsNonFinite(float* out_value) const {
94  if (GetType() == TYPE_NONFINITE) {
95    PickleIterator iter(pickle_);
96    return iter.ReadFloat(out_value);
97  } else {
98    return false;
99  }
100}
101
102bool GinJavaBridgeValue::GetAsObjectID(int32* out_object_id) const {
103  if (GetType() == TYPE_OBJECT_ID) {
104    PickleIterator iter(pickle_);
105    return iter.ReadInt(out_object_id);
106  } else {
107    return false;
108  }
109}
110
111GinJavaBridgeValue::GinJavaBridgeValue(Type type) :
112    pickle_(sizeof(Header)) {
113  Header* header = pickle_.headerT<Header>();
114  header->magic = kHeaderMagic;
115  header->type = type;
116}
117
118GinJavaBridgeValue::GinJavaBridgeValue(const base::BinaryValue* value)
119    : pickle_(value->GetBuffer(), value->GetSize()) {
120  DCHECK(ContainsGinJavaBridgeValue(value));
121}
122
123base::BinaryValue* GinJavaBridgeValue::SerializeToBinaryValue() {
124  return base::BinaryValue::CreateWithCopiedBuffer(
125      reinterpret_cast<const char*>(pickle_.data()), pickle_.size());
126}
127
128}  // namespace content
129