1// Copyright (c) 2012 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 "sync/syncable/entry_kernel.h"
6
7#include "base/strings/string_number_conversions.h"
8#include "sync/protocol/proto_value_conversions.h"
9#include "sync/syncable/syncable_enum_conversions.h"
10#include "sync/util/cryptographer.h"
11
12namespace syncer {
13namespace syncable {
14
15EntryKernel::EntryKernel() : dirty_(false) {
16  // Everything else should already be default-initialized.
17  for (int i = INT64_FIELDS_BEGIN; i < INT64_FIELDS_END; ++i) {
18    int64_fields[i] = 0;
19  }
20}
21
22EntryKernel::~EntryKernel() {}
23
24ModelType EntryKernel::GetModelType() const {
25  ModelType specifics_type = GetModelTypeFromSpecifics(ref(SPECIFICS));
26  if (specifics_type != UNSPECIFIED)
27    return specifics_type;
28  if (ref(ID).IsRoot())
29    return TOP_LEVEL_FOLDER;
30  // Loose check for server-created top-level folders that aren't
31  // bound to a particular model type.
32  if (!ref(UNIQUE_SERVER_TAG).empty() && ref(SERVER_IS_DIR))
33    return TOP_LEVEL_FOLDER;
34
35  return UNSPECIFIED;
36}
37
38ModelType EntryKernel::GetServerModelType() const {
39  ModelType specifics_type = GetModelTypeFromSpecifics(ref(SERVER_SPECIFICS));
40  if (specifics_type != UNSPECIFIED)
41    return specifics_type;
42  if (ref(ID).IsRoot())
43    return TOP_LEVEL_FOLDER;
44  // Loose check for server-created top-level folders that aren't
45  // bound to a particular model type.
46  if (!ref(UNIQUE_SERVER_TAG).empty() && ref(SERVER_IS_DIR))
47    return TOP_LEVEL_FOLDER;
48
49  return UNSPECIFIED;
50}
51
52bool EntryKernel::ShouldMaintainPosition() const {
53  // We maintain positions for all bookmarks, except those that are
54  // server-created top-level folders.
55  return (GetModelTypeFromSpecifics(ref(SPECIFICS)) == syncer::BOOKMARKS)
56      && !(!ref(UNIQUE_SERVER_TAG).empty() && ref(IS_DIR));
57}
58
59namespace {
60
61// Utility function to loop through a set of enum values and add the
62// field keys/values in the kernel to the given dictionary.
63//
64// V should be convertible to Value.
65template <class T, class U, class V>
66void SetFieldValues(const EntryKernel& kernel,
67                    base::DictionaryValue* dictionary_value,
68                    const char* (*enum_key_fn)(T),
69                    V* (*enum_value_fn)(U),
70                    int field_key_min, int field_key_max) {
71  DCHECK_LE(field_key_min, field_key_max);
72  for (int i = field_key_min; i <= field_key_max; ++i) {
73    T field = static_cast<T>(i);
74    const std::string& key = enum_key_fn(field);
75    V* value = enum_value_fn(kernel.ref(field));
76    dictionary_value->Set(key, value);
77  }
78}
79
80void SetEncryptableProtoValues(
81    const EntryKernel& kernel,
82    Cryptographer* cryptographer,
83    base::DictionaryValue* dictionary_value,
84    int field_key_min, int field_key_max) {
85  DCHECK_LE(field_key_min, field_key_max);
86  for (int i = field_key_min; i <= field_key_max; ++i) {
87    ProtoField field = static_cast<ProtoField>(i);
88    const std::string& key = GetProtoFieldString(field);
89
90    base::DictionaryValue* value = NULL;
91    sync_pb::EntitySpecifics decrypted;
92    const sync_pb::EncryptedData& encrypted = kernel.ref(field).encrypted();
93    if (cryptographer &&
94        kernel.ref(field).has_encrypted() &&
95        cryptographer->CanDecrypt(encrypted) &&
96        cryptographer->Decrypt(encrypted, &decrypted)) {
97      value = EntitySpecificsToValue(decrypted);
98      value->SetBoolean("encrypted", true);
99    } else {
100      value = EntitySpecificsToValue(kernel.ref(field));
101    }
102    dictionary_value->Set(key, value);
103  }
104}
105
106// Helper functions for SetFieldValues().
107
108base::StringValue* Int64ToValue(int64 i) {
109  return new base::StringValue(base::Int64ToString(i));
110}
111
112base::StringValue* TimeToValue(const base::Time& t) {
113  return new base::StringValue(GetTimeDebugString(t));
114}
115
116base::StringValue* IdToValue(const Id& id) {
117  return id.ToValue();
118}
119
120base::FundamentalValue* BooleanToValue(bool bool_val) {
121  return new base::FundamentalValue(bool_val);
122}
123
124base::StringValue* StringToValue(const std::string& str) {
125  return new base::StringValue(str);
126}
127
128base::StringValue* UniquePositionToValue(const UniquePosition& pos) {
129  return base::Value::CreateStringValue(pos.ToDebugString());
130}
131
132}  // namespace
133
134base::DictionaryValue* EntryKernel::ToValue(
135    Cryptographer* cryptographer) const {
136  base::DictionaryValue* kernel_info = new base::DictionaryValue();
137  kernel_info->SetBoolean("isDirty", is_dirty());
138  kernel_info->Set("serverModelType", ModelTypeToValue(GetServerModelType()));
139
140  // Int64 fields.
141  SetFieldValues(*this, kernel_info,
142                 &GetMetahandleFieldString, &Int64ToValue,
143                 INT64_FIELDS_BEGIN, META_HANDLE);
144  SetFieldValues(*this, kernel_info,
145                 &GetBaseVersionString, &Int64ToValue,
146                 META_HANDLE + 1, BASE_VERSION);
147  SetFieldValues(*this, kernel_info,
148                 &GetInt64FieldString, &Int64ToValue,
149                 BASE_VERSION + 1, INT64_FIELDS_END - 1);
150
151  // Time fields.
152  SetFieldValues(*this, kernel_info,
153                 &GetTimeFieldString, &TimeToValue,
154                 TIME_FIELDS_BEGIN, TIME_FIELDS_END - 1);
155
156  // ID fields.
157  SetFieldValues(*this, kernel_info,
158                 &GetIdFieldString, &IdToValue,
159                 ID_FIELDS_BEGIN, ID_FIELDS_END - 1);
160
161  // Bit fields.
162  SetFieldValues(*this, kernel_info,
163                 &GetIndexedBitFieldString, &BooleanToValue,
164                 BIT_FIELDS_BEGIN, INDEXED_BIT_FIELDS_END - 1);
165  SetFieldValues(*this, kernel_info,
166                 &GetIsDelFieldString, &BooleanToValue,
167                 INDEXED_BIT_FIELDS_END, IS_DEL);
168  SetFieldValues(*this, kernel_info,
169                 &GetBitFieldString, &BooleanToValue,
170                 IS_DEL + 1, BIT_FIELDS_END - 1);
171
172  // String fields.
173  {
174    // Pick out the function overload we want.
175    SetFieldValues(*this, kernel_info,
176                   &GetStringFieldString, &StringToValue,
177                   STRING_FIELDS_BEGIN, STRING_FIELDS_END - 1);
178  }
179
180  // Proto fields.
181  SetEncryptableProtoValues(*this, cryptographer, kernel_info,
182                            PROTO_FIELDS_BEGIN, PROTO_FIELDS_END - 1);
183
184  // UniquePosition fields
185  SetFieldValues(*this, kernel_info,
186                 &GetUniquePositionFieldString, &UniquePositionToValue,
187                 UNIQUE_POSITION_FIELDS_BEGIN, UNIQUE_POSITION_FIELDS_END - 1);
188
189  // Bit temps.
190  SetFieldValues(*this, kernel_info,
191                 &GetBitTempString, &BooleanToValue,
192                 BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1);
193
194  return kernel_info;
195}
196
197base::ListValue* EntryKernelMutationMapToValue(
198    const EntryKernelMutationMap& mutations) {
199  base::ListValue* list = new base::ListValue();
200  for (EntryKernelMutationMap::const_iterator it = mutations.begin();
201       it != mutations.end(); ++it) {
202    list->Append(EntryKernelMutationToValue(it->second));
203  }
204  return list;
205}
206
207base::DictionaryValue* EntryKernelMutationToValue(
208    const EntryKernelMutation& mutation) {
209  base::DictionaryValue* dict = new base::DictionaryValue();
210  dict->Set("original", mutation.original.ToValue(NULL));
211  dict->Set("mutated", mutation.mutated.ToValue(NULL));
212  return dict;
213}
214
215}  // namespace syncer
216}  // namespace syncable
217