// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "sync/syncable/entry_kernel.h" #include "base/strings/string_number_conversions.h" #include "sync/protocol/proto_value_conversions.h" #include "sync/syncable/syncable_enum_conversions.h" #include "sync/util/cryptographer.h" namespace syncer { namespace syncable { EntryKernel::EntryKernel() : dirty_(false) { // Everything else should already be default-initialized. for (int i = INT64_FIELDS_BEGIN; i < INT64_FIELDS_END; ++i) { int64_fields[i] = 0; } } EntryKernel::~EntryKernel() {} ModelType EntryKernel::GetModelType() const { ModelType specifics_type = GetModelTypeFromSpecifics(ref(SPECIFICS)); if (specifics_type != UNSPECIFIED) return specifics_type; if (ref(ID).IsRoot()) return TOP_LEVEL_FOLDER; // Loose check for server-created top-level folders that aren't // bound to a particular model type. if (!ref(UNIQUE_SERVER_TAG).empty() && ref(SERVER_IS_DIR)) return TOP_LEVEL_FOLDER; return UNSPECIFIED; } ModelType EntryKernel::GetServerModelType() const { ModelType specifics_type = GetModelTypeFromSpecifics(ref(SERVER_SPECIFICS)); if (specifics_type != UNSPECIFIED) return specifics_type; if (ref(ID).IsRoot()) return TOP_LEVEL_FOLDER; // Loose check for server-created top-level folders that aren't // bound to a particular model type. if (!ref(UNIQUE_SERVER_TAG).empty() && ref(SERVER_IS_DIR)) return TOP_LEVEL_FOLDER; return UNSPECIFIED; } bool EntryKernel::ShouldMaintainPosition() const { // We maintain positions for all bookmarks, except those that are // server-created top-level folders. return (GetModelTypeFromSpecifics(ref(SPECIFICS)) == syncer::BOOKMARKS) && !(!ref(UNIQUE_SERVER_TAG).empty() && ref(IS_DIR)); } bool EntryKernel::ShouldMaintainHierarchy() const { // We maintain hierarchy for bookmarks, device info, and top-level folders, // but no other types. Note that the Nigori node consists of a single // top-level folder, so it's included in this set. return (GetModelTypeFromSpecifics(ref(SPECIFICS)) == syncer::BOOKMARKS) || (!ref(UNIQUE_SERVER_TAG).empty()); } namespace { // Utility function to loop through a set of enum values and add the // field keys/values in the kernel to the given dictionary. // // V should be convertible to Value. template void 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) { DCHECK_LE(field_key_min, field_key_max); for (int i = field_key_min; i <= field_key_max; ++i) { T field = static_cast(i); const std::string& key = enum_key_fn(field); V* value = enum_value_fn(kernel.ref(field)); dictionary_value->Set(key, value); } } void SetEncryptableProtoValues( const EntryKernel& kernel, Cryptographer* cryptographer, base::DictionaryValue* dictionary_value, int field_key_min, int field_key_max) { DCHECK_LE(field_key_min, field_key_max); for (int i = field_key_min; i <= field_key_max; ++i) { ProtoField field = static_cast(i); const std::string& key = GetProtoFieldString(field); base::DictionaryValue* value = NULL; sync_pb::EntitySpecifics decrypted; const sync_pb::EncryptedData& encrypted = kernel.ref(field).encrypted(); if (cryptographer && kernel.ref(field).has_encrypted() && cryptographer->CanDecrypt(encrypted) && cryptographer->Decrypt(encrypted, &decrypted)) { value = EntitySpecificsToValue(decrypted); value->SetBoolean("encrypted", true); } else { value = EntitySpecificsToValue(kernel.ref(field)); } dictionary_value->Set(key, value); } } // Helper functions for SetFieldValues(). base::StringValue* Int64ToValue(int64 i) { return new base::StringValue(base::Int64ToString(i)); } base::StringValue* TimeToValue(const base::Time& t) { return new base::StringValue(GetTimeDebugString(t)); } base::StringValue* IdToValue(const Id& id) { return id.ToValue(); } base::FundamentalValue* BooleanToValue(bool bool_val) { return new base::FundamentalValue(bool_val); } base::StringValue* StringToValue(const std::string& str) { return new base::StringValue(str); } base::StringValue* UniquePositionToValue(const UniquePosition& pos) { return new base::StringValue(pos.ToDebugString()); } base::StringValue* AttachmentMetadataToValue( const sync_pb::AttachmentMetadata& a) { return new base::StringValue(a.SerializeAsString()); } } // namespace base::DictionaryValue* EntryKernel::ToValue( Cryptographer* cryptographer) const { base::DictionaryValue* kernel_info = new base::DictionaryValue(); kernel_info->SetBoolean("isDirty", is_dirty()); kernel_info->Set("serverModelType", ModelTypeToValue(GetServerModelType())); // Int64 fields. SetFieldValues(*this, kernel_info, &GetMetahandleFieldString, &Int64ToValue, INT64_FIELDS_BEGIN, META_HANDLE); SetFieldValues(*this, kernel_info, &GetBaseVersionString, &Int64ToValue, META_HANDLE + 1, BASE_VERSION); SetFieldValues(*this, kernel_info, &GetInt64FieldString, &Int64ToValue, BASE_VERSION + 1, INT64_FIELDS_END - 1); // Time fields. SetFieldValues(*this, kernel_info, &GetTimeFieldString, &TimeToValue, TIME_FIELDS_BEGIN, TIME_FIELDS_END - 1); // ID fields. SetFieldValues(*this, kernel_info, &GetIdFieldString, &IdToValue, ID_FIELDS_BEGIN, ID_FIELDS_END - 1); // Bit fields. SetFieldValues(*this, kernel_info, &GetIndexedBitFieldString, &BooleanToValue, BIT_FIELDS_BEGIN, INDEXED_BIT_FIELDS_END - 1); SetFieldValues(*this, kernel_info, &GetIsDelFieldString, &BooleanToValue, INDEXED_BIT_FIELDS_END, IS_DEL); SetFieldValues(*this, kernel_info, &GetBitFieldString, &BooleanToValue, IS_DEL + 1, BIT_FIELDS_END - 1); // String fields. { // Pick out the function overload we want. SetFieldValues(*this, kernel_info, &GetStringFieldString, &StringToValue, STRING_FIELDS_BEGIN, STRING_FIELDS_END - 1); } // Proto fields. SetEncryptableProtoValues(*this, cryptographer, kernel_info, PROTO_FIELDS_BEGIN, PROTO_FIELDS_END - 1); // UniquePosition fields SetFieldValues(*this, kernel_info, &GetUniquePositionFieldString, &UniquePositionToValue, UNIQUE_POSITION_FIELDS_BEGIN, UNIQUE_POSITION_FIELDS_END - 1); // AttachmentMetadata fields SetFieldValues(*this, kernel_info, &GetAttachmentMetadataFieldString, &AttachmentMetadataToValue, ATTACHMENT_METADATA_FIELDS_BEGIN, ATTACHMENT_METADATA_FIELDS_END - 1); // Bit temps. SetFieldValues(*this, kernel_info, &GetBitTempString, &BooleanToValue, BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1); return kernel_info; } base::ListValue* EntryKernelMutationMapToValue( const EntryKernelMutationMap& mutations) { base::ListValue* list = new base::ListValue(); for (EntryKernelMutationMap::const_iterator it = mutations.begin(); it != mutations.end(); ++it) { list->Append(EntryKernelMutationToValue(it->second)); } return list; } base::DictionaryValue* EntryKernelMutationToValue( const EntryKernelMutation& mutation) { base::DictionaryValue* dict = new base::DictionaryValue(); dict->Set("original", mutation.original.ToValue(NULL)); dict->Set("mutated", mutation.mutated.ToValue(NULL)); return dict; } } // namespace syncer } // namespace syncable