15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_codec.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/json/json_string_value_serializer.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/bookmarks/browser/bookmark_model.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "grit/components_strings.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)namespace bookmarks {
216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kRootsKey = "roots";
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kRootFolderNameKey = "bookmark_bar";
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kOtherBookmarkFolderNameKey = "other";
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The value is left as 'synced' for historical reasons.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kMobileBookmarkFolderNameKey = "synced";
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kVersionKey = "version";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kChecksumKey = "checksum";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kIdKey = "id";
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kTypeKey = "type";
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kNameKey = "name";
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kDateAddedKey = "date_added";
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kURLKey = "url";
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kDateModifiedKey = "date_modified";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kChildrenKey = "children";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kMetaInfo = "meta_info";
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const char* BookmarkCodec::kSyncTransactionVersion = "sync_transaction_version";
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kTypeURL = "url";
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BookmarkCodec::kTypeFolder = "folder";
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Current version of the file.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kCurrentVersion = 1;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkCodec::BookmarkCodec()
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : ids_reassigned_(false),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ids_valid_(true),
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      maximum_id_(0),
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      model_sync_transaction_version_(
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          BookmarkNode::kInvalidSyncTransactionVersion) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkCodec::~BookmarkCodec() {}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::Value* BookmarkCodec::Encode(BookmarkModel* model) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Encode(model->bookmark_bar_node(),
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                model->other_node(),
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                model->mobile_node(),
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                model->root_node()->GetMetaInfoMap(),
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                model->root_node()->sync_transaction_version());
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::Value* BookmarkCodec::Encode(
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const BookmarkNode* bookmark_bar_node,
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const BookmarkNode* other_folder_node,
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const BookmarkNode* mobile_folder_node,
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const BookmarkNode::MetaInfoMap* model_meta_info_map,
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int64 sync_transaction_version) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ids_reassigned_ = false;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitializeChecksum();
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* roots = new base::DictionaryValue();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  roots->Set(kRootFolderNameKey, EncodeNode(bookmark_bar_node));
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  roots->Set(kOtherBookmarkFolderNameKey, EncodeNode(other_folder_node));
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  roots->Set(kMobileBookmarkFolderNameKey, EncodeNode(mobile_folder_node));
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (model_meta_info_map)
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    roots->Set(kMetaInfo, EncodeMetaInfo(*model_meta_info_map));
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (sync_transaction_version !=
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      BookmarkNode::kInvalidSyncTransactionVersion) {
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    roots->SetString(kSyncTransactionVersion,
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                     base::Int64ToString(sync_transaction_version));
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* main = new base::DictionaryValue();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  main->SetInteger(kVersionKey, kCurrentVersion);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FinalizeChecksum();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We are going to store the computed checksum. So set stored checksum to be
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the same as computed checksum.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stored_checksum_ = computed_checksum_;
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  main->Set(kChecksumKey, new base::StringValue(computed_checksum_));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  main->Set(kRootsKey, roots);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return main;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkCodec::Decode(BookmarkNode* bb_node,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           BookmarkNode* other_folder_node,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           BookmarkNode* mobile_folder_node,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           int64* max_id,
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           const base::Value& value) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ids_.clear();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ids_reassigned_ = false;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ids_valid_ = true;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  maximum_id_ = 0;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stored_checksum_.clear();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitializeChecksum();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = DecodeHelper(bb_node, other_folder_node, mobile_folder_node,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              value);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FinalizeChecksum();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If either the checksums differ or some IDs were missing/not unique,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reassign IDs.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ids_valid_ || computed_checksum() != stored_checksum())
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReassignIDs(bb_node, other_folder_node, mobile_folder_node);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *max_id = maximum_id_ + 1;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::Value* BookmarkCodec::EncodeNode(const BookmarkNode* node) {
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* value = new base::DictionaryValue();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string id = base::Int64ToString(node->id());
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->SetString(kIdKey, id);
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const base::string16& title = node->GetTitle();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->SetString(kNameKey, title);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->SetString(kDateAddedKey,
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   base::Int64ToString(node->date_added().ToInternalValue()));
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_url()) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->SetString(kTypeKey, kTypeURL);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string url = node->url().possibly_invalid_spec();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->SetString(kURLKey, url);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateChecksumWithUrlNode(id, title, url);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->SetString(kTypeKey, kTypeFolder);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->SetString(kDateModifiedKey,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     base::Int64ToString(node->date_folder_modified().
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   ToInternalValue()));
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateChecksumWithFolderNode(id, title);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::ListValue* child_values = new base::ListValue();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->Set(kChildrenKey, child_values);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < node->child_count(); ++i)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      child_values->Append(EncodeNode(node->GetChild(i)));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const BookmarkNode::MetaInfoMap* meta_info_map = node->GetMetaInfoMap();
140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (meta_info_map)
141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    value->Set(kMetaInfo, EncodeMetaInfo(*meta_info_map));
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (node->sync_transaction_version() !=
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      BookmarkNode::kInvalidSyncTransactionVersion) {
144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    value->SetString(kSyncTransactionVersion,
145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                     base::Int64ToString(node->sync_transaction_version()));
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)base::Value* BookmarkCodec::EncodeMetaInfo(
151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const BookmarkNode::MetaInfoMap& meta_info_map) {
152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::DictionaryValue* meta_info = new base::DictionaryValue;
153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (BookmarkNode::MetaInfoMap::const_iterator it = meta_info_map.begin();
154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      it != meta_info_map.end(); ++it) {
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    meta_info->SetStringWithoutPathExpansion(it->first, it->second);
156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return meta_info;
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkCodec::DecodeHelper(BookmarkNode* bb_node,
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 BookmarkNode* other_folder_node,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 BookmarkNode* mobile_folder_node,
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 const base::Value& value) {
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (value.GetType() != base::Value::TYPE_DICTIONARY)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Unexpected type.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::DictionaryValue& d_value =
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<const base::DictionaryValue&>(value);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int version;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!d_value.GetInteger(kVersionKey, &version) || version != kCurrentVersion)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Unknown version.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::Value* checksum_value;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (d_value.Get(kChecksumKey, &checksum_value)) {
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (checksum_value->GetType() != base::Value::TYPE_STRING)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!checksum_value->GetAsString(&stored_checksum_))
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::Value* roots;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!d_value.Get(kRootsKey, &roots))
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // No roots.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (roots->GetType() != base::Value::TYPE_DICTIONARY)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Invalid type for roots.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::DictionaryValue* roots_d_value =
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<const base::DictionaryValue*>(roots);
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::Value* root_folder_value;
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::Value* other_folder_value = NULL;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!roots_d_value->Get(kRootFolderNameKey, &root_folder_value) ||
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      root_folder_value->GetType() != base::Value::TYPE_DICTIONARY ||
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !roots_d_value->Get(kOtherBookmarkFolderNameKey, &other_folder_value) ||
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      other_folder_value->GetType() != base::Value::TYPE_DICTIONARY) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Invalid type for root folder and/or other
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   // folder.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DecodeNode(*static_cast<const base::DictionaryValue*>(root_folder_value),
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             NULL, bb_node);
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DecodeNode(*static_cast<const base::DictionaryValue*>(other_folder_value),
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             NULL, other_folder_node);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fail silently if we can't deserialize mobile bookmarks. We can't require
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them to exist in order to be backwards-compatible with older versions of
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // chrome.
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::Value* mobile_folder_value;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (roots_d_value->Get(kMobileBookmarkFolderNameKey, &mobile_folder_value) &&
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      mobile_folder_value->GetType() == base::Value::TYPE_DICTIONARY) {
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DecodeNode(*static_cast<const base::DictionaryValue*>(mobile_folder_value),
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               NULL, mobile_folder_node);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we didn't find the mobile folder, we're almost guaranteed to have a
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // duplicate id when we add the mobile folder. Consequently, if we don't
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // intend to reassign ids in the future (ids_valid_ is still true), then at
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // least reassign the mobile bookmarks to avoid it colliding with anything
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // else.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ids_valid_)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReassignIDsHelper(mobile_folder_node);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!DecodeMetaInfo(*roots_d_value, &model_meta_info_map_,
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                      &model_sync_transaction_version_))
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string sync_transaction_version_str;
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (roots_d_value->GetString(kSyncTransactionVersion,
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                               &sync_transaction_version_str) &&
230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      !base::StringToInt64(sync_transaction_version_str,
231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           &model_sync_transaction_version_))
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Need to reset the type as decoding resets the type to FOLDER. Similarly
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we need to reset the title as the title is persisted and restored from
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the file.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bb_node->set_type(BookmarkNode::BOOKMARK_BAR);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_folder_node->set_type(BookmarkNode::OTHER_NODE);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mobile_folder_node->set_type(BookmarkNode::MOBILE);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bb_node->SetTitle(l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_FOLDER_NAME));
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_folder_node->SetTitle(
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME));
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mobile_folder_node->SetTitle(
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME));
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool BookmarkCodec::DecodeChildren(const base::ListValue& child_value_list,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   BookmarkNode* parent) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < child_value_list.GetSize(); ++i) {
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Value* child_value;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!child_value_list.Get(i, &child_value))
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (child_value->GetType() != base::Value::TYPE_DICTIONARY)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DecodeNode(*static_cast<const base::DictionaryValue*>(child_value),
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               parent, NULL);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool BookmarkCodec::DecodeNode(const base::DictionaryValue& value,
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               BookmarkNode* parent,
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               BookmarkNode* node) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If no |node| is specified, we'll create one and add it to the |parent|.
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Therefore, in that case, |parent| must be non-NULL.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node && !parent) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string id_string;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 id = 0;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ids_valid_) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.GetString(kIdKey, &id_string) ||
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !base::StringToInt64(id_string, &id) ||
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ids_.count(id) != 0) {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ids_valid_ = false;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ids_.insert(id);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  maximum_id_ = std::max(maximum_id_, id);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
289a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 title;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value.GetString(kNameKey, &title);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string date_added_string;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value.GetString(kDateAddedKey, &date_added_string))
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    date_added_string = base::Int64ToString(Time::Now().ToInternalValue());
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 internal_time;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StringToInt64(date_added_string, &internal_time);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string type_string;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value.GetString(kTypeKey, &type_string))
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type_string != kTypeURL && type_string != kTypeFolder)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Unknown type.
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type_string == kTypeURL) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string url_string;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.GetString(kURLKey, &url_string))
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL url = GURL(url_string);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!node && url.is_valid())
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      node = new BookmarkNode(id, url);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;  // Node invalid.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent->Add(node, parent->child_count());
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    node->set_type(BookmarkNode::URL);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateChecksumWithUrlNode(id_string, title, url_string);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string last_modified_date;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.GetString(kDateModifiedKey, &last_modified_date))
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_modified_date = base::Int64ToString(Time::Now().ToInternalValue());
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Value* child_values;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.Get(kChildrenKey, &child_values))
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (child_values->GetType() != base::Value::TYPE_LIST)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!node) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      node = new BookmarkNode(id, GURL());
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If a new node is not created, explicitly assign ID to the existing one.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      node->set_id(id);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    node->set_type(BookmarkNode::FOLDER);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 internal_time;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::StringToInt64(last_modified_date, &internal_time);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    node->set_date_folder_modified(Time::FromInternalValue(internal_time));
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent->Add(node, parent->child_count());
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateChecksumWithFolderNode(id_string, title);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!DecodeChildren(*static_cast<const base::ListValue*>(child_values),
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        node)) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  node->SetTitle(title);
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  node->set_date_added(Time::FromInternalValue(internal_time));
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int64 sync_transaction_version = node->sync_transaction_version();
359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BookmarkNode::MetaInfoMap meta_info_map;
360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!DecodeMetaInfo(value, &meta_info_map, &sync_transaction_version))
361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  node->SetMetaInfoMap(meta_info_map);
363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string sync_transaction_version_str;
365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (value.GetString(kSyncTransactionVersion, &sync_transaction_version_str) &&
366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      !base::StringToInt64(sync_transaction_version_str,
367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           &sync_transaction_version))
368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  node->set_sync_transaction_version(sync_transaction_version);
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool BookmarkCodec::DecodeMetaInfo(const base::DictionaryValue& value,
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                   BookmarkNode::MetaInfoMap* meta_info_map,
377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                   int64* sync_transaction_version) {
378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(meta_info_map);
379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(sync_transaction_version);
380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  meta_info_map->clear();
381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const base::Value* meta_info;
383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!value.Get(kMetaInfo, &meta_info))
384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return true;
385f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<base::Value> deserialized_holder;
387f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
388f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Meta info used to be stored as a serialized dictionary, so attempt to
389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // parse the value as one.
390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (meta_info->IsType(base::Value::TYPE_STRING)) {
391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string meta_info_str;
392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    meta_info->GetAsString(&meta_info_str);
393f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    JSONStringValueSerializer serializer(meta_info_str);
394f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    deserialized_holder.reset(serializer.Deserialize(NULL, NULL));
395f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!deserialized_holder)
396f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return false;
397f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    meta_info = deserialized_holder.get();
398f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
399f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // meta_info is now either the kMetaInfo node, or the deserialized node if it
400f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // was stored as a string. Either way it should now be a (possibly nested)
401f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // dictionary of meta info values.
402f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const base::DictionaryValue* meta_info_dict;
403f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!meta_info->GetAsDictionary(&meta_info_dict))
404f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
405f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DecodeMetaInfoHelper(*meta_info_dict, std::string(), meta_info_map);
406f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
407f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Previously sync transaction version was stored in the meta info field
408f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // using this key. If the key is present when decoding, set the sync
409f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // transaction version to its value, then delete the field.
410f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (deserialized_holder) {
411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const char kBookmarkTransactionVersionKey[] = "sync.transaction_version";
412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BookmarkNode::MetaInfoMap::iterator it =
413f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        meta_info_map->find(kBookmarkTransactionVersionKey);
414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (it != meta_info_map->end()) {
415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::StringToInt64(it->second, sync_transaction_version);
416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      meta_info_map->erase(it);
417f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
418f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
419f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
420f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return true;
421f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
422f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
423f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void BookmarkCodec::DecodeMetaInfoHelper(
424f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::DictionaryValue& dict,
425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& prefix,
426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BookmarkNode::MetaInfoMap* meta_info_map) {
427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
428f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (it.value().IsType(base::Value::TYPE_DICTIONARY)) {
429f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const base::DictionaryValue* subdict;
430f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      it.value().GetAsDictionary(&subdict);
431f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DecodeMetaInfoHelper(*subdict, prefix + it.key() + ".", meta_info_map);
432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else if (it.value().IsType(base::Value::TYPE_STRING)) {
433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      it.value().GetAsString(&(*meta_info_map)[prefix + it.key()]);
434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
437f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::ReassignIDs(BookmarkNode* bb_node,
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                BookmarkNode* other_node,
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                BookmarkNode* mobile_node) {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  maximum_id_ = 0;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReassignIDsHelper(bb_node);
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReassignIDsHelper(other_node);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReassignIDsHelper(mobile_node);
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ids_reassigned_ = true;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::ReassignIDsHelper(BookmarkNode* node) {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(node);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  node->set_id(++maximum_id_);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < node->child_count(); ++i)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReassignIDsHelper(node->GetChild(i));
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::UpdateChecksum(const std::string& str) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Update(&md5_context_, str);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
459a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BookmarkCodec::UpdateChecksum(const base::string16& str) {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Update(&md5_context_,
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  base::StringPiece(
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      reinterpret_cast<const char*>(str.data()),
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      str.length() * sizeof(str[0])));
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::UpdateChecksumWithUrlNode(const std::string& id,
467a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                              const base::string16& title,
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              const std::string& url) {
469010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(base::IsStringUTF8(url));
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(id);
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(title);
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(kTypeURL);
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(url);
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::UpdateChecksumWithFolderNode(const std::string& id,
477a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                 const base::string16& title) {
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(id);
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(title);
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateChecksum(kTypeFolder);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::InitializeChecksum() {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Init(&md5_context_);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkCodec::FinalizeChecksum() {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Digest digest;
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Final(&digest, &md5_context_);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  computed_checksum_ = base::MD5DigestToBase16(digest);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
4936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}  // namespace bookmarks
494