普通文本  |  238行  |  7.89 KB

// 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 <class T, class U, class V>
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<T>(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<ProtoField>(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