// 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