// Copyright 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.h"
#include <iomanip>
#include "base/json/string_escape.h"
#include "base/strings/string_util.h"
#include "sync/syncable/blob.h"
#include "sync/syncable/directory.h"
#include "sync/syncable/syncable_base_transaction.h"
#include "sync/syncable/syncable_columns.h"
using std::string;
namespace syncer {
namespace syncable {
Entry::Entry(BaseTransaction* trans, GetById, const Id& id)
: basetrans_(trans) {
kernel_ = trans->directory()->GetEntryById(id);
}
Entry::Entry(BaseTransaction* trans, GetByClientTag, const string& tag)
: basetrans_(trans) {
kernel_ = trans->directory()->GetEntryByClientTag(tag);
}
Entry::Entry(BaseTransaction* trans, GetTypeRoot, ModelType type)
: basetrans_(trans) {
const std::string& tag = ModelTypeToRootTag(type);
kernel_ = trans->directory()->GetEntryByServerTag(tag);
}
Entry::Entry(BaseTransaction* trans, GetByHandle, int64 metahandle)
: basetrans_(trans) {
kernel_ = trans->directory()->GetEntryByHandle(metahandle);
}
Entry::Entry(BaseTransaction* trans, GetByServerTag, const string& tag)
: basetrans_(trans) {
kernel_ = trans->directory()->GetEntryByServerTag(tag);
}
Directory* Entry::dir() const {
return basetrans_->directory();
}
base::DictionaryValue* Entry::ToValue(Cryptographer* cryptographer) const {
base::DictionaryValue* entry_info = new base::DictionaryValue();
entry_info->SetBoolean("good", good());
if (good()) {
entry_info->Set("kernel", kernel_->ToValue(cryptographer));
entry_info->Set("modelType",
ModelTypeToValue(GetModelType()));
entry_info->SetBoolean("existsOnClientBecauseNameIsNonEmpty",
ExistsOnClientBecauseNameIsNonEmpty());
entry_info->SetBoolean("isRoot", IsRoot());
}
return entry_info;
}
ModelType Entry::GetServerModelType() const {
ModelType specifics_type = kernel_->GetServerModelType();
if (specifics_type != UNSPECIFIED)
return specifics_type;
// Otherwise, we don't have a server type yet. That should only happen
// if the item is an uncommitted locally created item.
// It's possible we'll need to relax these checks in the future; they're
// just here for now as a safety measure.
DCHECK(GetIsUnsynced());
DCHECK_EQ(GetServerVersion(), 0);
DCHECK(GetServerIsDel());
// Note: can't enforce !GetId().ServerKnows() here because that could
// actually happen if we hit AttemptReuniteLostCommitResponses.
return UNSPECIFIED;
}
ModelType Entry::GetModelType() const {
ModelType specifics_type = GetModelTypeFromSpecifics(GetSpecifics());
if (specifics_type != UNSPECIFIED)
return specifics_type;
if (IsRoot())
return TOP_LEVEL_FOLDER;
// Loose check for server-created top-level folders that aren't
// bound to a particular model type.
if (!GetUniqueServerTag().empty() && GetIsDir())
return TOP_LEVEL_FOLDER;
return UNSPECIFIED;
}
Id Entry::GetPredecessorId() const {
return dir()->GetPredecessorId(kernel_);
}
Id Entry::GetSuccessorId() const {
return dir()->GetSuccessorId(kernel_);
}
Id Entry::GetFirstChildId() const {
return dir()->GetFirstChildId(basetrans_, kernel_);
}
void Entry::GetChildHandles(std::vector<int64>* result) const {
dir()->GetChildHandlesById(basetrans_, GetId(), result);
}
int Entry::GetTotalNodeCount() const {
return dir()->GetTotalNodeCount(basetrans_, kernel_);
}
int Entry::GetPositionIndex() const {
return dir()->GetPositionIndex(basetrans_, kernel_);
}
bool Entry::ShouldMaintainPosition() const {
return kernel_->ShouldMaintainPosition();
}
bool Entry::ShouldMaintainHierarchy() const {
return kernel_->ShouldMaintainHierarchy();
}
std::ostream& operator<<(std::ostream& s, const Blob& blob) {
for (Blob::const_iterator i = blob.begin(); i != blob.end(); ++i)
s << std::hex << std::setw(2)
<< std::setfill('0') << static_cast<unsigned int>(*i);
return s << std::dec;
}
std::ostream& operator<<(std::ostream& os, const Entry& entry) {
int i;
EntryKernel* const kernel = entry.kernel_;
for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) {
os << g_metas_columns[i].name << ": "
<< kernel->ref(static_cast<Int64Field>(i)) << ", ";
}
for ( ; i < TIME_FIELDS_END; ++i) {
os << g_metas_columns[i].name << ": "
<< GetTimeDebugString(kernel->ref(static_cast<TimeField>(i))) << ", ";
}
for ( ; i < ID_FIELDS_END; ++i) {
os << g_metas_columns[i].name << ": "
<< kernel->ref(static_cast<IdField>(i)) << ", ";
}
os << "Flags: ";
for ( ; i < BIT_FIELDS_END; ++i) {
if (kernel->ref(static_cast<BitField>(i)))
os << g_metas_columns[i].name << ", ";
}
for ( ; i < STRING_FIELDS_END; ++i) {
const std::string& field = kernel->ref(static_cast<StringField>(i));
os << g_metas_columns[i].name << ": " << field << ", ";
}
for ( ; i < PROTO_FIELDS_END; ++i) {
std::string escaped_str = base::EscapeBytesAsInvalidJSONString(
kernel->ref(static_cast<ProtoField>(i)).SerializeAsString(),
false);
os << g_metas_columns[i].name << ": " << escaped_str << ", ";
}
for ( ; i < UNIQUE_POSITION_FIELDS_END; ++i) {
os << g_metas_columns[i].name << ": "
<< kernel->ref(static_cast<UniquePositionField>(i)).ToDebugString()
<< ", ";
}
for ( ; i < ATTACHMENT_METADATA_FIELDS_END; ++i) {
std::string escaped_str = base::EscapeBytesAsInvalidJSONString(
kernel->ref(static_cast<AttachmentMetadataField>(i))
.SerializeAsString(),
false);
os << g_metas_columns[i].name << ": " << escaped_str << ", ";
}
os << "TempFlags: ";
for ( ; i < BIT_TEMPS_END; ++i) {
if (kernel->ref(static_cast<BitTemp>(i)))
os << "#" << i - BIT_TEMPS_BEGIN << ", ";
}
return os;
}
} // namespace syncable
} // namespace syncer