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.
5 #include "sync/syncable/entry_kernel.h"
7 #include "base/json/string_escape.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "sync/protocol/proto_value_conversions.h"
10 #include "sync/syncable/syncable_columns.h"
11 #include "sync/syncable/syncable_enum_conversions.h"
12 #include "sync/util/cryptographer.h"
17 EntryKernel::EntryKernel() : dirty_(false) {
18 // Everything else should already be default-initialized.
19 for (int i
= 0; i
< INT64_FIELDS_COUNT
; ++i
) {
24 EntryKernel::~EntryKernel() {}
26 ModelType
EntryKernel::GetModelType() const {
27 ModelType specifics_type
= GetModelTypeFromSpecifics(ref(SPECIFICS
));
28 if (specifics_type
!= UNSPECIFIED
)
29 return specifics_type
;
31 return TOP_LEVEL_FOLDER
;
32 // Loose check for server-created top-level folders that aren't
33 // bound to a particular model type.
34 if (!ref(UNIQUE_SERVER_TAG
).empty() && ref(SERVER_IS_DIR
))
35 return TOP_LEVEL_FOLDER
;
40 ModelType
EntryKernel::GetServerModelType() const {
41 ModelType specifics_type
= GetModelTypeFromSpecifics(ref(SERVER_SPECIFICS
));
42 if (specifics_type
!= UNSPECIFIED
)
43 return specifics_type
;
45 return TOP_LEVEL_FOLDER
;
46 // Loose check for server-created top-level folders that aren't
47 // bound to a particular model type.
48 if (!ref(UNIQUE_SERVER_TAG
).empty() && ref(SERVER_IS_DIR
))
49 return TOP_LEVEL_FOLDER
;
54 bool EntryKernel::ShouldMaintainPosition() const {
55 // We maintain positions for all bookmarks, except those that are
56 // server-created top-level folders.
57 return TypeSupportsOrdering(GetModelTypeFromSpecifics(ref(SPECIFICS
))) &&
58 !(!ref(UNIQUE_SERVER_TAG
).empty() && ref(IS_DIR
));
61 bool EntryKernel::ShouldMaintainHierarchy() const {
62 // We maintain hierarchy for bookmarks and top-level folders,
63 // but no other types. Note that the Nigori node consists of a single
64 // top-level folder, so it's included in this set.
65 return TypeSupportsHierarchy(GetModelTypeFromSpecifics(ref(SPECIFICS
))) ||
66 (!ref(UNIQUE_SERVER_TAG
).empty());
71 // Utility function to loop through a set of enum values and add the
72 // field keys/values in the kernel to the given dictionary.
74 // V should be convertible to Value.
75 template <class T
, class U
, class V
>
76 void SetFieldValues(const EntryKernel
& kernel
,
77 base::DictionaryValue
* dictionary_value
,
78 const char* (*enum_key_fn
)(T
),
79 V
* (*enum_value_fn
)(U
),
80 int field_key_min
, int field_key_max
) {
81 DCHECK_LE(field_key_min
, field_key_max
);
82 for (int i
= field_key_min
; i
<= field_key_max
; ++i
) {
83 T field
= static_cast<T
>(i
);
84 const std::string
& key
= enum_key_fn(field
);
85 V
* value
= enum_value_fn(kernel
.ref(field
));
86 dictionary_value
->Set(key
, value
);
90 void SetEncryptableProtoValues(
91 const EntryKernel
& kernel
,
92 Cryptographer
* cryptographer
,
93 base::DictionaryValue
* dictionary_value
,
94 int field_key_min
, int field_key_max
) {
95 DCHECK_LE(field_key_min
, field_key_max
);
96 for (int i
= field_key_min
; i
<= field_key_max
; ++i
) {
97 ProtoField field
= static_cast<ProtoField
>(i
);
98 const std::string
& key
= GetProtoFieldString(field
);
100 scoped_ptr
<base::DictionaryValue
> value
;
101 sync_pb::EntitySpecifics decrypted
;
102 const sync_pb::EncryptedData
& encrypted
= kernel
.ref(field
).encrypted();
104 kernel
.ref(field
).has_encrypted() &&
105 cryptographer
->CanDecrypt(encrypted
) &&
106 cryptographer
->Decrypt(encrypted
, &decrypted
)) {
107 value
= EntitySpecificsToValue(decrypted
);
108 value
->SetBoolean("encrypted", true);
110 value
= EntitySpecificsToValue(kernel
.ref(field
));
112 dictionary_value
->Set(key
, value
.Pass());
116 // Helper functions for SetFieldValues().
118 base::StringValue
* Int64ToValue(int64 i
) {
119 return new base::StringValue(base::Int64ToString(i
));
122 base::StringValue
* TimeToValue(const base::Time
& t
) {
123 return new base::StringValue(GetTimeDebugString(t
));
126 base::StringValue
* IdToValue(const Id
& id
) {
130 base::FundamentalValue
* BooleanToValue(bool bool_val
) {
131 return new base::FundamentalValue(bool_val
);
134 base::StringValue
* StringToValue(const std::string
& str
) {
135 return new base::StringValue(str
);
138 base::StringValue
* UniquePositionToValue(const UniquePosition
& pos
) {
139 return new base::StringValue(pos
.ToDebugString());
142 base::StringValue
* AttachmentMetadataToValue(
143 const sync_pb::AttachmentMetadata
& a
) {
144 return new base::StringValue(a
.SerializeAsString());
149 base::DictionaryValue
* EntryKernel::ToValue(
150 Cryptographer
* cryptographer
) const {
151 base::DictionaryValue
* kernel_info
= new base::DictionaryValue();
152 kernel_info
->SetBoolean("isDirty", is_dirty());
153 ModelType dataType
= GetServerModelType();
154 if (!IsRealDataType(dataType
))
155 dataType
= GetModelType();
156 kernel_info
->Set("modelType", ModelTypeToValue(dataType
));
159 SetFieldValues(*this, kernel_info
,
160 &GetMetahandleFieldString
, &Int64ToValue
,
161 INT64_FIELDS_BEGIN
, META_HANDLE
);
162 SetFieldValues(*this, kernel_info
,
163 &GetBaseVersionString
, &Int64ToValue
,
164 META_HANDLE
+ 1, BASE_VERSION
);
165 SetFieldValues(*this, kernel_info
,
166 &GetInt64FieldString
, &Int64ToValue
,
167 BASE_VERSION
+ 1, INT64_FIELDS_END
- 1);
170 SetFieldValues(*this, kernel_info
,
171 &GetTimeFieldString
, &TimeToValue
,
172 TIME_FIELDS_BEGIN
, TIME_FIELDS_END
- 1);
175 SetFieldValues(*this, kernel_info
,
176 &GetIdFieldString
, &IdToValue
,
177 ID_FIELDS_BEGIN
, ID_FIELDS_END
- 1);
180 SetFieldValues(*this, kernel_info
,
181 &GetIndexedBitFieldString
, &BooleanToValue
,
182 BIT_FIELDS_BEGIN
, INDEXED_BIT_FIELDS_END
- 1);
183 SetFieldValues(*this, kernel_info
,
184 &GetIsDelFieldString
, &BooleanToValue
,
185 INDEXED_BIT_FIELDS_END
, IS_DEL
);
186 SetFieldValues(*this, kernel_info
,
187 &GetBitFieldString
, &BooleanToValue
,
188 IS_DEL
+ 1, BIT_FIELDS_END
- 1);
192 // Pick out the function overload we want.
193 SetFieldValues(*this, kernel_info
,
194 &GetStringFieldString
, &StringToValue
,
195 STRING_FIELDS_BEGIN
, STRING_FIELDS_END
- 1);
199 SetEncryptableProtoValues(*this, cryptographer
, kernel_info
,
200 PROTO_FIELDS_BEGIN
, PROTO_FIELDS_END
- 1);
202 // UniquePosition fields
203 SetFieldValues(*this, kernel_info
,
204 &GetUniquePositionFieldString
, &UniquePositionToValue
,
205 UNIQUE_POSITION_FIELDS_BEGIN
, UNIQUE_POSITION_FIELDS_END
- 1);
207 // AttachmentMetadata fields
208 SetFieldValues(*this,
210 &GetAttachmentMetadataFieldString
,
211 &AttachmentMetadataToValue
,
212 ATTACHMENT_METADATA_FIELDS_BEGIN
,
213 ATTACHMENT_METADATA_FIELDS_END
- 1);
216 SetFieldValues(*this, kernel_info
,
217 &GetBitTempString
, &BooleanToValue
,
218 BIT_TEMPS_BEGIN
, BIT_TEMPS_END
- 1);
223 base::ListValue
* EntryKernelMutationMapToValue(
224 const EntryKernelMutationMap
& mutations
) {
225 base::ListValue
* list
= new base::ListValue();
226 for (EntryKernelMutationMap::const_iterator it
= mutations
.begin();
227 it
!= mutations
.end(); ++it
) {
228 list
->Append(EntryKernelMutationToValue(it
->second
));
233 base::DictionaryValue
* EntryKernelMutationToValue(
234 const EntryKernelMutation
& mutation
) {
235 base::DictionaryValue
* dict
= new base::DictionaryValue();
236 dict
->Set("original", mutation
.original
.ToValue(NULL
));
237 dict
->Set("mutated", mutation
.mutated
.ToValue(NULL
));
241 std::ostream
& operator<<(std::ostream
& os
, const EntryKernel
& entry_kernel
) {
243 EntryKernel
* const kernel
= const_cast<EntryKernel
*>(&entry_kernel
);
244 for (i
= BEGIN_FIELDS
; i
< INT64_FIELDS_END
; ++i
) {
245 os
<< g_metas_columns
[i
].name
<< ": "
246 << kernel
->ref(static_cast<Int64Field
>(i
)) << ", ";
248 for (; i
< TIME_FIELDS_END
; ++i
) {
249 os
<< g_metas_columns
[i
].name
<< ": "
250 << GetTimeDebugString(kernel
->ref(static_cast<TimeField
>(i
))) << ", ";
252 for (; i
< ID_FIELDS_END
; ++i
) {
253 os
<< g_metas_columns
[i
].name
<< ": "
254 << kernel
->ref(static_cast<IdField
>(i
)) << ", ";
257 for (; i
< BIT_FIELDS_END
; ++i
) {
258 if (kernel
->ref(static_cast<BitField
>(i
)))
259 os
<< g_metas_columns
[i
].name
<< ", ";
261 for (; i
< STRING_FIELDS_END
; ++i
) {
262 const std::string
& field
= kernel
->ref(static_cast<StringField
>(i
));
263 os
<< g_metas_columns
[i
].name
<< ": " << field
<< ", ";
265 for (; i
< PROTO_FIELDS_END
; ++i
) {
266 std::string escaped_str
= base::EscapeBytesAsInvalidJSONString(
267 kernel
->ref(static_cast<ProtoField
>(i
)).SerializeAsString(), false);
268 os
<< g_metas_columns
[i
].name
<< ": " << escaped_str
<< ", ";
270 for (; i
< UNIQUE_POSITION_FIELDS_END
; ++i
) {
271 os
<< g_metas_columns
[i
].name
<< ": "
272 << kernel
->ref(static_cast<UniquePositionField
>(i
)).ToDebugString()
275 for (; i
< ATTACHMENT_METADATA_FIELDS_END
; ++i
) {
276 std::string escaped_str
= base::EscapeBytesAsInvalidJSONString(
277 kernel
->ref(static_cast<AttachmentMetadataField
>(i
))
278 .SerializeAsString(),
280 os
<< g_metas_columns
[i
].name
<< ": " << escaped_str
<< ", ";
283 for (; i
< BIT_TEMPS_END
; ++i
) {
284 if (kernel
->ref(static_cast<BitTemp
>(i
)))
285 os
<< "#" << i
- BIT_TEMPS_BEGIN
<< ", ";
290 } // namespace syncer
291 } // namespace syncable