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 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 22 EntryKernel::~EntryKernel() {} 23 24 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 38 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 52 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 bool EntryKernel::ShouldMaintainHierarchy() const { 60 // We maintain hierarchy for bookmarks, device info, and top-level folders, 61 // but no other types. Note that the Nigori node consists of a single 62 // top-level folder, so it's included in this set. 63 return (GetModelTypeFromSpecifics(ref(SPECIFICS)) == syncer::BOOKMARKS) 64 || (!ref(UNIQUE_SERVER_TAG).empty()); 65 } 66 67 namespace { 68 69 // Utility function to loop through a set of enum values and add the 70 // field keys/values in the kernel to the given dictionary. 71 // 72 // V should be convertible to Value. 73 template <class T, class U, class V> 74 void SetFieldValues(const EntryKernel& kernel, 75 base::DictionaryValue* dictionary_value, 76 const char* (*enum_key_fn)(T), 77 V* (*enum_value_fn)(U), 78 int field_key_min, int field_key_max) { 79 DCHECK_LE(field_key_min, field_key_max); 80 for (int i = field_key_min; i <= field_key_max; ++i) { 81 T field = static_cast<T>(i); 82 const std::string& key = enum_key_fn(field); 83 V* value = enum_value_fn(kernel.ref(field)); 84 dictionary_value->Set(key, value); 85 } 86 } 87 88 void SetEncryptableProtoValues( 89 const EntryKernel& kernel, 90 Cryptographer* cryptographer, 91 base::DictionaryValue* dictionary_value, 92 int field_key_min, int field_key_max) { 93 DCHECK_LE(field_key_min, field_key_max); 94 for (int i = field_key_min; i <= field_key_max; ++i) { 95 ProtoField field = static_cast<ProtoField>(i); 96 const std::string& key = GetProtoFieldString(field); 97 98 base::DictionaryValue* value = NULL; 99 sync_pb::EntitySpecifics decrypted; 100 const sync_pb::EncryptedData& encrypted = kernel.ref(field).encrypted(); 101 if (cryptographer && 102 kernel.ref(field).has_encrypted() && 103 cryptographer->CanDecrypt(encrypted) && 104 cryptographer->Decrypt(encrypted, &decrypted)) { 105 value = EntitySpecificsToValue(decrypted); 106 value->SetBoolean("encrypted", true); 107 } else { 108 value = EntitySpecificsToValue(kernel.ref(field)); 109 } 110 dictionary_value->Set(key, value); 111 } 112 } 113 114 // Helper functions for SetFieldValues(). 115 116 base::StringValue* Int64ToValue(int64 i) { 117 return new base::StringValue(base::Int64ToString(i)); 118 } 119 120 base::StringValue* TimeToValue(const base::Time& t) { 121 return new base::StringValue(GetTimeDebugString(t)); 122 } 123 124 base::StringValue* IdToValue(const Id& id) { 125 return id.ToValue(); 126 } 127 128 base::FundamentalValue* BooleanToValue(bool bool_val) { 129 return new base::FundamentalValue(bool_val); 130 } 131 132 base::StringValue* StringToValue(const std::string& str) { 133 return new base::StringValue(str); 134 } 135 136 base::StringValue* UniquePositionToValue(const UniquePosition& pos) { 137 return new base::StringValue(pos.ToDebugString()); 138 } 139 140 base::StringValue* AttachmentMetadataToValue( 141 const sync_pb::AttachmentMetadata& a) { 142 return new base::StringValue(a.SerializeAsString()); 143 } 144 145 } // namespace 146 147 base::DictionaryValue* EntryKernel::ToValue( 148 Cryptographer* cryptographer) const { 149 base::DictionaryValue* kernel_info = new base::DictionaryValue(); 150 kernel_info->SetBoolean("isDirty", is_dirty()); 151 kernel_info->Set("serverModelType", ModelTypeToValue(GetServerModelType())); 152 153 // Int64 fields. 154 SetFieldValues(*this, kernel_info, 155 &GetMetahandleFieldString, &Int64ToValue, 156 INT64_FIELDS_BEGIN, META_HANDLE); 157 SetFieldValues(*this, kernel_info, 158 &GetBaseVersionString, &Int64ToValue, 159 META_HANDLE + 1, BASE_VERSION); 160 SetFieldValues(*this, kernel_info, 161 &GetInt64FieldString, &Int64ToValue, 162 BASE_VERSION + 1, INT64_FIELDS_END - 1); 163 164 // Time fields. 165 SetFieldValues(*this, kernel_info, 166 &GetTimeFieldString, &TimeToValue, 167 TIME_FIELDS_BEGIN, TIME_FIELDS_END - 1); 168 169 // ID fields. 170 SetFieldValues(*this, kernel_info, 171 &GetIdFieldString, &IdToValue, 172 ID_FIELDS_BEGIN, ID_FIELDS_END - 1); 173 174 // Bit fields. 175 SetFieldValues(*this, kernel_info, 176 &GetIndexedBitFieldString, &BooleanToValue, 177 BIT_FIELDS_BEGIN, INDEXED_BIT_FIELDS_END - 1); 178 SetFieldValues(*this, kernel_info, 179 &GetIsDelFieldString, &BooleanToValue, 180 INDEXED_BIT_FIELDS_END, IS_DEL); 181 SetFieldValues(*this, kernel_info, 182 &GetBitFieldString, &BooleanToValue, 183 IS_DEL + 1, BIT_FIELDS_END - 1); 184 185 // String fields. 186 { 187 // Pick out the function overload we want. 188 SetFieldValues(*this, kernel_info, 189 &GetStringFieldString, &StringToValue, 190 STRING_FIELDS_BEGIN, STRING_FIELDS_END - 1); 191 } 192 193 // Proto fields. 194 SetEncryptableProtoValues(*this, cryptographer, kernel_info, 195 PROTO_FIELDS_BEGIN, PROTO_FIELDS_END - 1); 196 197 // UniquePosition fields 198 SetFieldValues(*this, kernel_info, 199 &GetUniquePositionFieldString, &UniquePositionToValue, 200 UNIQUE_POSITION_FIELDS_BEGIN, UNIQUE_POSITION_FIELDS_END - 1); 201 202 // AttachmentMetadata fields 203 SetFieldValues(*this, 204 kernel_info, 205 &GetAttachmentMetadataFieldString, 206 &AttachmentMetadataToValue, 207 ATTACHMENT_METADATA_FIELDS_BEGIN, 208 ATTACHMENT_METADATA_FIELDS_END - 1); 209 210 // Bit temps. 211 SetFieldValues(*this, kernel_info, 212 &GetBitTempString, &BooleanToValue, 213 BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1); 214 215 return kernel_info; 216 } 217 218 base::ListValue* EntryKernelMutationMapToValue( 219 const EntryKernelMutationMap& mutations) { 220 base::ListValue* list = new base::ListValue(); 221 for (EntryKernelMutationMap::const_iterator it = mutations.begin(); 222 it != mutations.end(); ++it) { 223 list->Append(EntryKernelMutationToValue(it->second)); 224 } 225 return list; 226 } 227 228 base::DictionaryValue* EntryKernelMutationToValue( 229 const EntryKernelMutation& mutation) { 230 base::DictionaryValue* dict = new base::DictionaryValue(); 231 dict->Set("original", mutation.original.ToValue(NULL)); 232 dict->Set("mutated", mutation.mutated.ToValue(NULL)); 233 return dict; 234 } 235 236 } // namespace syncer 237 } // namespace syncable 238