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
12 namespace syncer {
13 namespace syncable {
14
EntryKernel()15 EntryKernel::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
~EntryKernel()22 EntryKernel::~EntryKernel() {}
23
GetModelType() const24 ModelType 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
GetServerModelType() const38 ModelType 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
ShouldMaintainPosition() const52 bool 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
59 namespace {
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.
65 template <class T, class U, class V>
SetFieldValues(const EntryKernel & kernel,base::DictionaryValue * dictionary_value,const char * (* enum_key_fn)(T),V * (* enum_value_fn)(U),int field_key_min,int field_key_max)66 void 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
SetEncryptableProtoValues(const EntryKernel & kernel,Cryptographer * cryptographer,base::DictionaryValue * dictionary_value,int field_key_min,int field_key_max)80 void 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
Int64ToValue(int64 i)108 base::StringValue* Int64ToValue(int64 i) {
109 return new base::StringValue(base::Int64ToString(i));
110 }
111
TimeToValue(const base::Time & t)112 base::StringValue* TimeToValue(const base::Time& t) {
113 return new base::StringValue(GetTimeDebugString(t));
114 }
115
IdToValue(const Id & id)116 base::StringValue* IdToValue(const Id& id) {
117 return id.ToValue();
118 }
119
BooleanToValue(bool bool_val)120 base::FundamentalValue* BooleanToValue(bool bool_val) {
121 return new base::FundamentalValue(bool_val);
122 }
123
StringToValue(const std::string & str)124 base::StringValue* StringToValue(const std::string& str) {
125 return new base::StringValue(str);
126 }
127
UniquePositionToValue(const UniquePosition & pos)128 base::StringValue* UniquePositionToValue(const UniquePosition& pos) {
129 return new base::StringValue(pos.ToDebugString());
130 }
131
AttachmentMetadataToValue(const sync_pb::AttachmentMetadata & a)132 base::StringValue* AttachmentMetadataToValue(
133 const sync_pb::AttachmentMetadata& a) {
134 return new base::StringValue(a.SerializeAsString());
135 }
136
137 } // namespace
138
ToValue(Cryptographer * cryptographer) const139 base::DictionaryValue* EntryKernel::ToValue(
140 Cryptographer* cryptographer) const {
141 base::DictionaryValue* kernel_info = new base::DictionaryValue();
142 kernel_info->SetBoolean("isDirty", is_dirty());
143 kernel_info->Set("serverModelType", ModelTypeToValue(GetServerModelType()));
144
145 // Int64 fields.
146 SetFieldValues(*this, kernel_info,
147 &GetMetahandleFieldString, &Int64ToValue,
148 INT64_FIELDS_BEGIN, META_HANDLE);
149 SetFieldValues(*this, kernel_info,
150 &GetBaseVersionString, &Int64ToValue,
151 META_HANDLE + 1, BASE_VERSION);
152 SetFieldValues(*this, kernel_info,
153 &GetInt64FieldString, &Int64ToValue,
154 BASE_VERSION + 1, INT64_FIELDS_END - 1);
155
156 // Time fields.
157 SetFieldValues(*this, kernel_info,
158 &GetTimeFieldString, &TimeToValue,
159 TIME_FIELDS_BEGIN, TIME_FIELDS_END - 1);
160
161 // ID fields.
162 SetFieldValues(*this, kernel_info,
163 &GetIdFieldString, &IdToValue,
164 ID_FIELDS_BEGIN, ID_FIELDS_END - 1);
165
166 // Bit fields.
167 SetFieldValues(*this, kernel_info,
168 &GetIndexedBitFieldString, &BooleanToValue,
169 BIT_FIELDS_BEGIN, INDEXED_BIT_FIELDS_END - 1);
170 SetFieldValues(*this, kernel_info,
171 &GetIsDelFieldString, &BooleanToValue,
172 INDEXED_BIT_FIELDS_END, IS_DEL);
173 SetFieldValues(*this, kernel_info,
174 &GetBitFieldString, &BooleanToValue,
175 IS_DEL + 1, BIT_FIELDS_END - 1);
176
177 // String fields.
178 {
179 // Pick out the function overload we want.
180 SetFieldValues(*this, kernel_info,
181 &GetStringFieldString, &StringToValue,
182 STRING_FIELDS_BEGIN, STRING_FIELDS_END - 1);
183 }
184
185 // Proto fields.
186 SetEncryptableProtoValues(*this, cryptographer, kernel_info,
187 PROTO_FIELDS_BEGIN, PROTO_FIELDS_END - 1);
188
189 // UniquePosition fields
190 SetFieldValues(*this, kernel_info,
191 &GetUniquePositionFieldString, &UniquePositionToValue,
192 UNIQUE_POSITION_FIELDS_BEGIN, UNIQUE_POSITION_FIELDS_END - 1);
193
194 // AttachmentMetadata fields
195 SetFieldValues(*this,
196 kernel_info,
197 &GetAttachmentMetadataFieldString,
198 &AttachmentMetadataToValue,
199 ATTACHMENT_METADATA_FIELDS_BEGIN,
200 ATTACHMENT_METADATA_FIELDS_END - 1);
201
202 // Bit temps.
203 SetFieldValues(*this, kernel_info,
204 &GetBitTempString, &BooleanToValue,
205 BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1);
206
207 return kernel_info;
208 }
209
EntryKernelMutationMapToValue(const EntryKernelMutationMap & mutations)210 base::ListValue* EntryKernelMutationMapToValue(
211 const EntryKernelMutationMap& mutations) {
212 base::ListValue* list = new base::ListValue();
213 for (EntryKernelMutationMap::const_iterator it = mutations.begin();
214 it != mutations.end(); ++it) {
215 list->Append(EntryKernelMutationToValue(it->second));
216 }
217 return list;
218 }
219
EntryKernelMutationToValue(const EntryKernelMutation & mutation)220 base::DictionaryValue* EntryKernelMutationToValue(
221 const EntryKernelMutation& mutation) {
222 base::DictionaryValue* dict = new base::DictionaryValue();
223 dict->Set("original", mutation.original.ToValue(NULL));
224 dict->Set("mutated", mutation.mutated.ToValue(NULL));
225 return dict;
226 }
227
228 } // namespace syncer
229 } // namespace syncable
230